PPIx-Regexp-0.055000755000765000024 013237102475 12662 5ustar00tomstaff000000000000PPIx-Regexp-0.055/Build.PL000444000765000024 161613237102475 14317 0ustar00tomstaff000000000000use 5.006; use strict; use warnings; use lib qw{ inc }; use Module::Build; use My::Module::Build; use My::Module::Meta; (my $mbv = Module::Build->VERSION()) =~ s/_//g; my $meta = My::Module::Meta->new(); my %args = ( dist_author => 'Thomas R. Wyant, III F', dist_abstract => 'Parse regular expressions', module_name => 'PPIx::Regexp', build_requires => $meta->build_requires(), requires => $meta->requires( perl => $meta->requires_perl(), ), license => 'perl', add_to_cleanup => [ qw{ cover_db } ], ); $mbv >= 0.28 and $args{meta_merge} = $meta->meta_merge(); # Don't require Module::Build when building distribution, because user # can use ExtUtils::MakeMaker. $mbv >= 0.34 and $args{auto_configure_requires} = !$meta->distribution(); my $bldr = My::Module::Build->new (%args); $bldr->create_build_script (); # ex: set textwidth=72 : PPIx-Regexp-0.055/Changes000444000765000024 6250513237102475 14342 0ustar00tomstaff0000000000000.055 2018-02-08 T. R. Wyant Tokenizer method prior() is now fatal. This was documented as package-private, but as it WAS documented, I am putting it through a deprecation cycle anyway. Six months from now it will be removed. Add Script_Run classes as subclasses to their superclass docs. This was missed in the last update. 0.054 2018-01-29 T. R. Wyant Add support for (+script_run:...). This is an experimental feature added in Perl 5.27.8. It imposes on any matches it contains the additional restriction that everything matched has to belong to the same Unicode script. This support will be retracted if the functionality does not make it into Perl 5.28. Add method scontent(). This returns significant content only. That is, if called on the parse of '/ f u b a r /x', it returns '/fubar/x'. 0.053 2017-10-30 T. R. Wyant Recognize \px as Unicode char class. At least, when the x is C, L, M, N, P, S or Z. The 'parse' argument to new() is now deprecated. 0.052 2017-09-07 T. R. Wyant RT 122715: Clarify Node->find_parents() documentation. Thanks to Salvatore Bonaccorso for letting me know about this problem. Further deprecate tokenizer method prior() in favor of prior_significant_token(). Add requirements_for_perl(). This is analogous to the CPAN::Meta::Requirements method requirements_for_module(), though the output is formatted differently. Also put in the actual requirements for an un-escaped literal left curly after a constant, which was removed in 5.25.1 and reinstated in 5.27.1. Add accepts_perl(). This is analogous to CPAN::Meta::Requirements->accepts_module(). I decided that CPAN::Meta;:Requirements was overkill, but this may turn out to be the wrong decision, so I will be careful what I expose. Document behavior of perl_version_introduced() and perl_version_removed() when a feature is re-introduced after removal, or re-removed after re-introduction. \N{} (empty curlys) removed in 5.27.1. 0.051 2017-01-29 T. R. Wyant Support whitespace inside [] if /xx in effect. Starting with Perl 5.25.9, a space or tab appearing inside a bracketed character class is not significant if /xx is asserted. Further deprecate tokenizer method prior() Add 'provides' data to ExtUtils::MakeMaker output SOME unescaped litaral '{' removed in 5.025001. After '.', Unicode classes, and bracketed classes (including extended) they are still legal. Make /\b{/ an error Perl fails to parse the above, because once it sees the '\b{' it wants to find one of the extended boundary assertions (like \b{wb}), and declares an error when it does not. So we check for this and rebless the curly into an unknown token, not a literal. 0.050 2016-05-06 T. R. Wyant Parse bracketed substitution with embedded comment. This is something like s{foo}\n#{bar}\n{baz} which is equivalent to s/foo/baz/. PPI gets this wrong, and we're not smart enough to fix up the PPI parse, but if given this as text, we now parse it correctly. We now recognize postfix dereferences by default, since Perl does beginning with 5.24. In other words, default new() argument 'postderef' to true. Unterminated substitutions (i.e. 's//') should no longer cause an exception. Instead they parse as an unknown token. 0.049 2016-04-19 T. R. Wyant Robustify PPIx::Regexp->perl_version_removed() The problem here was that if the expression being parsed was sufficiently badly-formed, $self->delimiters() would be undef, throwing a warning. Correct dump of embedded modifiers (eg: (?i:...)) 0.048 2016-02-29 T. R. Wyant Add option 'strict', like 'use re "strict"' In the presence of strict(), I opted to set perl_version_introduced to the version of Perl where the construct became an error. Parse '\N{}' as no-op. The previous parse was a character class ('\N') followed by two literals ('{' and '}'). But perl5238delta said that it had been ignored up to that time. Starting with 5.23.8 it is an error if 'use re strict' is in effect. Quash 'NOT a POSIX class ...' warning under 5.23.8 Add Makefile targets authortest and testcover. 0.047 2016-01-29 T. R. Wyant Recognize \b{lb}, introduced in 5.23.7. If this is retracted before 5.24, it will be removed outright. 0.046 2016-01-08 T. R. Wyant Add GitHub repository to mmetadata. 0.045 2015-12-31 T. R. Wyant Deprecate tokenizer method prior() in favor of prior_significant_token(). This is not part of the public interface, so I suppose I could have just slam-dunked it, but ... Add ability to parse strings as well as regexes The new functionality is controlled by the new new() argument 'parse', whose permitted values are 'regex' (the default), 'string', or 'guess'. String parsing, and the 'string' and 'guess' values of 'parse', are experimental. 0.044 2015-12-08 T. R. Wyant Allow nesting of \Q with \U, \L, and \F The perlop docs say these nest with each other. Playing with Perl suggests that \U, \L and \F supersede each other, but thet they as a group nest with \Q in either order, so that if you specify \Q and one of the \U, \L, \F group you need two \Es to turn them all back off. Restrict recognition of back references in replacement strings to \number form, since Perl itself does not recognize \g{...} or \k{...} there. Recognize postfix dereference if desired. This is controlled by the Boolean argument 'postderef' passed to PPIx::Regexp->new(). The default is false, but will become true if postfix dereference becomes mainstream Perl 5. Add explain() and supporting methods main_structure() and in_regex_set(). The explain() method returns a brief explanation of what the element does. 0.043 2015-11-18 T. R. Wyant Do not end regex set prematurely on finding '])' The problem is that '])' can occur within an extended bracketed character class if it contains grouping parentheses and the last item in a group is a regular bracketed character class and there is no white space between the end of the character class and the end of the group. Record parse failure if switch condition is unknown The structure was being reblessed to PPIx::Regexp::Structure::Unknown, but the number of parse failures was not being incremented. Parse \U and friends as meta-characters inside \Q...\E This turns out to be what Perl itself does, as shown by $ perl -E 'say qr{\Q\Ufoo}' Clear error when lexer identifies unknown token. Those who peruse the changes in this release will see that a bunch of refactoring was done as part of this. Parse white space inside bracketed character classes inside extended bracketed character classes (whew!) as literals, except for the space character itself and the horizontal tab. This tracks the corresponding change in Perl 5.23.4. This will be reverted if the corresponding Perl change does not make it into 5.24.0. Beginning with version 0.035, PPIx::Regexp was incorrectly reporting the sense of modifiers when the same token both asserted and negated modifiers (e.g. '(?x-i:...)'). This release should correct the problem. Document policy when Perl changes in such a way that the proper parse for a regular expression changes. In this case the more modern parse is preferred. 0.042 2015-10-09 T. R. Wyant Report error rather than failing when parsing a string consisting wholly of white space. Group types were not being recognized if they contained the delimiter character for the regexp (e.g. in qr<(?\ the look-behind assertion was not recognized as such). Correct mis-parse of ' s///'. Leading white space is supposed to be acceptable, but the leading whitespace token caused PPIx::Regexp::Lexer not to recognize the substitution as such. Tokenizer was failing when the string to be parsed was so bad it was trying to return the whole thing as a single PPIx::Regexp::Token::Unknown. PPIx::Regexp::Dumper now displays a message if a structure is missing its end delimiter. RT 107331 Produce parse error in the presence of trailing cruft. Thanks to Klaus Rindfrey for catching this. The tokenizer now does a preliminary scan for delimiting brackets and modifiers. Anything after the modifiers except for white space is now made into a PPIx::Regexp::Token::Unknown, resulting in a parse failure being reported. The previous implementation simply assumed a valid expression, and in the case of the expression in the ticket blithely mismatched the delimiters and returned a parse without failures, but which was manifestly bogus. Tweak documentation in PPIx::Regexp. 0.041 2015-07-02 T. R. Wyant Report \C (match octet) as removed in 5.23.0. Accept non-ASCII whitespace under /x. The Whitespace object can be multiple characters; the perl_version_introduced() becomes '5.021001' if any of them is a code point above 127. The perl_version_removed() method now returns '5.021001' when called on a PPIx::Regexp object produced by parsing '?foo?' (match once without explicit 'm'). The object produced by parsing 'm?foo?' still returns the minimum Perl version. 0.040 2015-05-31 T. R. Wyant Do not parse unadorned parentheses as capture groups when /n is in effect. Instead, they are parsed as PPIx::Regexp::Structure. Named captures appear to be unaffected by /n. Made a verbose dump a little more so. Specifically, dump max_capture_group where relevant, and display dumped values a bit more informatively. Report /n (no captures) as having been added in 5.21.8. 0.039 2015-04-02 T. R. Wyant Recognize nested subscripts in interpolation. Thanks to Andy Lester for finding this, which actually manifested in Perl-Critic-Policy-Variables-ProhibitUnusedVarsStricter. The problem is that the actual heuristics for finding the end of an interpolation are undocumented, and I missed this rather-obvious case. Add \b{g} (= \b{gcb}) 0.038 2015-03-09 T. R. Wyant Make \b{foo} into an unknown token (and therefore an error. This applies to \b{anything}, where 'anything' is anything bur 'gcb', 'wb', or 'sb'. Handle the boundary assertions introduced in Perl 5.21.9: '\b{gcb}' (grapheme cluster boundary), '\b{wb}' (word boundary), '\b{sb}' (sentence boundary), and the corresponding '\B{...}' constructions. Similar-looking things like '\b{foo}' are not recognized as assertions, and end up being literals. This is less general than I usually make things, but was done against the possibility that (e.g.) '\b{foo}' might be introduced later, requiring perl_version_released() to return a different number. Any of these retracted prior to Perl 5.22.0 will simply be removed from PPIx::Regexp. 0.037 2014-11-12 T. R. Wyant Have PPIx::Regexp::Structure::RegexSet POD recognize that the Perl docs (specifically perlrecharclass) now call this construction Extended Bracketed Character Classes, not sets. Correctly mark the replacement portion of s///ee as code. Prior to this release it was parsed as though no /e were present. Make available the number of times a given modifier is asserted (except for the match semantics modifiers which get handled differently). See PPIx::Regexp::Token::Modifier->asserted() and PPIx::Regexp::Tokenizer->modifier() for details. 0.036 2014-01-04 T. R. Wyant Retract the "Allow non-ASCII white space under /x" change introduced in version 0.033. I misread perl5170delta, and implemented early. Change to explicit character class to recognize white space under /x. I was previously using \s, which matched too much. Thanks to Nobuo Kumagai for finding and reporting this. 0.035 2013-11-15 T. R. Wyant Properly handle multi-character modifiers like /ee. We now handle /eie as being the same as /eei. Thanks to Anonymous Monk for finding this. Properly handle \g and \k back references that do not correspond to an actual capture group. They are now reblessed into the unknown token, and counted as errors. Thanks to Anonymous Monk for finding this. Add method error() to PPIx::Regexp::Element. This should return an error message when the element is in error -- normally when it has been blessed into the unknown token or structure. Add method modifier_asserted() to PPIx::Regexp::Element. This walks the parse tree backward to determine if the given modifier is in effect for the element. 0.034 2013-05-11 T. R. Wyant Correct spelling and grammar errors in POD and comments. RT #85050. Thanks David Steinbrunner for catching these. Allow interpolation in regex sets. It implies Perl 5.17.9 or higher. Allow non-ASCII white space under /x. It implies Perl 5.17.9 or higher. Fix problems with Regex Set functionality under Perl 5.6.2. CPAN testers RULE! 0.031 2013-01-31 T. R. Wyant Have PPIx::Regexp::Token::Code (and offspring) become PPIx::Regexp::Token::Unknown inside a regex set. 0.030 2013-01-22 T. R. Wyant Add Regex Sets, which were added to Perl as an experimental feature in 5.17.8. This is experimental in Perl, therefore the parse may change. Ditch PPIx::Regexp::Token::GroupType method __expect_after_match() in favor of the more general __match_setup(). This is done without deprecation because __expect_after_match() was documeted as package-private, but noted in the change log because it _was_ documented. 0.029 2013-01-14 T. R. Wyant Add method unescaped_content() to PPIx::Regexp::Element(). Rewrite the tokenizing code in PPIx::Regexp::Token::GroupType and offspring to use regular expressions specific to the regexp delimiter, and escaping only that delimiter. Thanks again to Alexandr Ciornii for finding more of these. Fix mis-parse of /(\?|I)/ as a branch reset (it's really an alternation). There may be more of these lurking. Thanks to Alexandr Ciornii for finding this one. Add options -files and -objectify to eg/predump. 0.028 2012-06-06 T. R. Wyant Replace all uses of YAML::Any with YAML, since they come in the same distro, and YAML does not suffer from deprecation warnings. 0.027 2012-05-28 T. R. Wyant Eliminate unescaped literal "{" characters in regexps in PPIx::Regexp::Token::Backreference and PPIx::Regexp::Token::CharClass::Simple. These are deprecated in 5.17.0. 0.026 2012-02-24 T. R. Wyant Add support for \F (fold case), added in 5.15.8. 0.025 2012-01-04 T. R. Wyant Tolerate leading and trailing white space around the regular expression. These are still round-trip safe, since the white space is tokenized. Make Changes file conform to CPAN::Changes, and add xt/author/changes.t to ensure continued compliance. 0.024 2011-12-17 T. R. Wyant Reinstate author test xt/author/manifest.t, which was clobbered shortly before the release of 0.021_10. 0.023 2011-12-08 T. R. Wyant Correct address of FSF in the version of the GPL distributed in LICENSES/Copying. Thanks to Petr Pisar for picking this up. 0.022 2011-11-24 T. R. Wyant Correct various documentation errors. Don't initialize effective modifiers with '^', since that wrongly asserts that /d has been seen somewhere along the line. Implement negation of match-semantic modifiers (e.g. 'no re /u;') by setting the relevant datum to undef. Support for default modifiers. This includes: * default_modifiers argument to new() in PPIx::Regexp, PPIx::Regexp::Tokenizer, and PPIx::Regexp::Dumper * Public method modifier_asserted() on PPIx::Regexp, to return whether a given modifier is actually in effect. The results of the modifier() method are unchanged. Require Test::More 0.88 for installation. Eliminate all the 'eval { require ... }' logic in favor of 'use Test::More 0.88'. Have Makefile.PL make use of {BUILD_REQUIRES} if it is available. Fix PPIx::Regexp::Token::Whitespace->can_be_quantified() to return false. 0.021 2011-07-22 T. R. Wyant Modified tokenizer to correctly handle a back slash used as a delimiter. I believe. PPIx::Regexp::Dumper now dumps the results of ppi() if that method is present and -verbose is asserted. 0.020 2011-04-02 T. R. Wyant Corrected perl_version_introduced(): * \R is now 5.009005 (was 5.000). 0.019 2011-03-01 T. R. Wyant Various corrections to perl_version_introduced(): * \X is now 5.006 (was 5.000); * \N{name} is now 5.006001 (was 5.006); * \N{U+xxxx} is now 5.008 (was 5.006). The \C is now parsed as a PPIx::Regexp::Token::CharClass::Simple. It was previously considered a PPIx::Regexp::Token::Literal. Ensure that \N{$foo} parses as a Unicode literal, not a quantified \N. The ordinal() method returns undef for this. Understand the /aa modifier, introduced with 5.13.10. Report perl_version_introduced() of 5.013010 for the new semantic modifiers when modifying the entire expression. Correct handling of interpolations like ${^foo} and $#{foo}. 0.018 2011-02-16 T. R. Wyant Override ppi() in PPIx::Regexp::Token::Interpolation to provide the proper PPI when variable names are bracketed. Properly parse bracketed variable names (I hope!), which may not be subscripted. Take account of possible '$' or '@' casts before a symbol in an interpolation (e.g. $$foo{bar}, which is equivalent to $foo->{bar}). Add the /a modifier to PPI::Regexp::Token::Modifiers, legal only in the (?:...) construction. This was introduced in Perl 5.13.9. When parsing an interpolation from a replacement string (rather than a regular expression), take subscripts at face value rather than trying to disambiguate them from quantifiers and character classes, which they can't be in this context. 0.016 2011-01-05 T. R. Wyant The PPIx::Regexp::Token::Code perl_version_introduced() method now returns the minimum Perl version (currently set to 5.000) if it is used to represent the substitution portion of s///e. 0.015 2010-10-25 T. R. Wyant Documented intent to revoke support for features introduced in a development Perl which do not make it to a production release. This is necessary because in this case the syntax could be reused with different semantics. Added support for Perl 5.13.6 (?^...) construction. Added support for Perl 5.13.6 d, l, and u modifiers. Fixed inconsistency in perl_version_introduced() results between PPIx::Regexp::Token::Modifier and PPIx::Regexp::Token::GroupType::Modifier. Corrected PPIx::Regexp::Constant RE_CAPTURE_NAME docs, somehow missed back at 0.010_01. 0.014 2010-10-14 T. R. Wyant Recognize \o{...} as a PPIx::Regexp::Token::Literal, with perl_version_introduced() of 5.0013003. Terminate \0.. through \7.. after three characters, as Perl does. These two were brought to my attention by Brian D. Foy's "The Effective Perler" for October 11 2010, http://www.effectiveperlprogramming.com/blog/697 Correct the PPIx::Regexp::Token::Literal ordinal() method for '\b'. As a literal, this is a back space. 0.013 2010-10-10 T. R. Wyant Declare a parse failure if characters are found between the '}' and the ')' of (?{...}) and (??{...}), and rebless the tokens to ::Unknown. Perl does not accept anything here, so I think I should not either. Whitespace tweak in the PPIx::Regexp::Dumper test output for the failures test. Replace the PPI logic in PPIx::Regexp::Token::Code with a call to $tokenizer->find_matching_delimiter(). This is actually the way Perl works, as a look at toke.c and regcomp.c makes clear. Push the perl_version_introduced() back to 5.0 at the request of Alexandr Ciornii, for the potential benefit of Perl::MinimumVersion. This was done mostly by reading the various perlre, perldelta, and perlop documents, so these should be taken with a HUGE grain of salt. 0.012 2010-09-26 T. R. Wyant Track all the features reported as introduced (or removed) in Perl 5.010 back to Perl 5.009005, and report them as such. Report modifier /r as having been introduced in Perl 5.013002, rather than the default of 5.006. 0.011 2010-09-16 T. R. Wyant Remove dependencies on Params::Util and Readonly. The latter was requested by ADAMK for the benefit of Padre. It involved changing the symbols exported from PPIx::Regexp::Constant, but these were documented as private, so ... Parse POSIX character classes [=a=] and [.a.] as PPIx::Regexp::Token::CharClass::POSIX::Unknown, which counts as a parse failure since these are not supported by Perl. Make the PPI::Document created by PPIx::Regexp::Token::Code->ppi() be read only. This means we need PPI 1.116. Cache the document, and ensure the cached result is returned on subsequent calls. 0.010 2010-08-06 T. R. Wyant Fix fatal error in PPIx::Regexp::Token::Code->ppi(). Move author tests from xt/ to xt/author/. 0.009 2010-08-03 T. R. Wyant Recognize s/.../.../ee as being different from s/.../.../e. In particular, the replacement portion of the former is _not_ a Perl expression: it's an interpolatble string, which later gets eval{}'ed. 0.008 2010-07-01 T. R. Wyant Promote methods can_be_quantified() and is_quantifier() from PPIx::Regexp::Token to PPIx::Regexp::Element, so all classes inherit them. They still return true and false respectively. Override can_be_quantified() to return false on PPIx::Regexp, PPIx::Regexp::Structure::Quantifier, PPIx::Regexp::Structure::Regexp, and PPIx::Regexp::Structure::Replacement. Override is_quantifier() to return true on PPIx::Regexp::Structure::Quantifier. Modify PPIx::Regexp::Dumper to be able to display can_be_quantified and is_quantifier for PPIx::Regexp::Node objects when dumping verbosely. Convert internal data to Readonly in PPIx::Regexp::Lexer, PPIx::Regexp::Token::CharClass::Simple, PPIx::Regexp::Token::Structure, and PPIx::Regexp::Tokenizer. Remove leftover boilerplate in PPIx::Regexp::Token::CharClass::Simple. Explicitly require a minimum Perl of 5.006. Centralized dependencies in inc/PPIx/Regexp/Meta.pm. Removed claim that PPIx::Regexp is alpha code. Docs still say that the interface can be changed, but now it will go through a deprecation cycle. 0.007 2010-04-28 T. R. Wyant PPIx::Regexp::Lexer no longer fails when encountering expressions like m{)}. Instead, it marks the right parenthesis as an unmatched delimiter. Fixed RT 56864 - PPIx::Regexp::Lexer fails in Perl::Critic under Perl 5.13.0. This was due to the value of a returned $+[0] getting transmogrified before the caller saw it. I never did isolate what triggered the bug. You can now get a tokenizer trace by setting environment value PPIX_REGEXP_TOKENIZER_TRACE to a non-zero numeric value. This is unsupported, though. 0.006 2010-02-26 T. R. Wyant Parse \N{...} in accordance with perl5115delta. The curlys must contain an alpha followed by alphanumerics, spaces, parens, colons, or dashes. \N{ without a matching } is a character class (if legal) followed by a literal '{'. Parse \N inside a character class as PPI::Regexp::Token::Unknown, since Perl 5.11.5 considers this a compile error. A \N{...} inside a character class is still OK. Add method match() to PPIx::Regexp::Tokenizer. This is analogous to capture(), but returns the entire matched string. 0.005 2009-12-26 T. R. Wyant Recognize \N (without curlys), back-ported from Perl 6 into 5.11. Recognize unicode characters as \N{[[:alpha:]] ... rather than \N{[\w\s:] ... This is per the 5.11 documentation, but I think Perl always worked this way. Recognize loose matching of Unicode character classes, and allow '=' in lieu of a single ':' in a Unicode character class (this from Perl 5.11.3). PPIx::Regexp::Dumper now produces the proper output when called with perl_version => 1, test => 1. Describe the typical content of the object in the documentation for PPIx::Regexp::Structure::NamedCapture and PPIx::Regexp::Token::GroupType::NamedCapture. 0.004 2009-11-09 T. R. Wyant Have PPIx::Regexp::Token::Literal correctly recognize when charnames::vianame() is unavailable, and decouple this from the handling of \N{U+hhhh}. Add dependency on Task::Weaken, since depending on Scalar::Util appears not to cut it. Correct the assignment of the license type in Makefile.PL. 0.003 2009-11-05 T. R. Wyant Have PPIx::Regexp::Token::Literal recognize \N{U+hhhh} (where hhhh represents hex digits), and provide its ordinal (hhhh). Remove recognition of \N. (. = any character), which Perl does not do. Fix $re->flush_cache() so that it actually removes $re and only $re from the cache. Add delimiters() method to PPIx::Regexp::Main and PPIx::Regexp. Support this in eg/prenav. Increase test coverage and remove dead code. Count tests in t/parse.t and t/unit.t 0.002 2009-10-28 T. R. Wyant In verbose mode, have PPIx::Regexp::Dumper dump the absolute capture number referred to by a numbered reference. Have eg/preslurp pass its -verbose option to PPIx::Regexp::Dumper Don't use Test::More::isa_ok for the t/basic.t class heritage tests, since some versions of Test::More require a reference for the first argument of isa_ok(). 0.001 2009-10-21 T. R. Wyant Initial release. # ex: set textwidth=72 autoindent : PPIx-Regexp-0.055/MANIFEST000444000765000024 554613237102475 14162 0ustar00tomstaff000000000000Build.PL Changes eg/interpolated eg/preaccepts eg/predump eg/prenav eg/preslurp eg/README inc/My/Module/Build.pm inc/My/Module/Meta.pm inc/My/Module/Mock_Tokenizer.pm inc/My/Module/Test.pm lib/PPIx/Regexp.pm lib/PPIx/Regexp/Constant.pm lib/PPIx/Regexp/Dumper.pm lib/PPIx/Regexp/Element.pm lib/PPIx/Regexp/Lexer.pm lib/PPIx/Regexp/Node.pm lib/PPIx/Regexp/Node/Range.pm lib/PPIx/Regexp/Node/Unknown.pm lib/PPIx/Regexp/StringTokenizer.pm lib/PPIx/Regexp/Structure.pm lib/PPIx/Regexp/Structure/Assertion.pm lib/PPIx/Regexp/Structure/BranchReset.pm lib/PPIx/Regexp/Structure/Capture.pm lib/PPIx/Regexp/Structure/CharClass.pm lib/PPIx/Regexp/Structure/Code.pm lib/PPIx/Regexp/Structure/Main.pm lib/PPIx/Regexp/Structure/Modifier.pm lib/PPIx/Regexp/Structure/NamedCapture.pm lib/PPIx/Regexp/Structure/Quantifier.pm lib/PPIx/Regexp/Structure/Regexp.pm lib/PPIx/Regexp/Structure/RegexSet.pm lib/PPIx/Regexp/Structure/Replacement.pm lib/PPIx/Regexp/Structure/Script_Run.pm lib/PPIx/Regexp/Structure/Subexpression.pm lib/PPIx/Regexp/Structure/Switch.pm lib/PPIx/Regexp/Structure/Unknown.pm lib/PPIx/Regexp/Support.pm lib/PPIx/Regexp/Token.pm lib/PPIx/Regexp/Token/Assertion.pm lib/PPIx/Regexp/Token/Backreference.pm lib/PPIx/Regexp/Token/Backtrack.pm lib/PPIx/Regexp/Token/CharClass.pm lib/PPIx/Regexp/Token/CharClass/POSIX.pm lib/PPIx/Regexp/Token/CharClass/POSIX/Unknown.pm lib/PPIx/Regexp/Token/CharClass/Simple.pm lib/PPIx/Regexp/Token/Code.pm lib/PPIx/Regexp/Token/Comment.pm lib/PPIx/Regexp/Token/Condition.pm lib/PPIx/Regexp/Token/Control.pm lib/PPIx/Regexp/Token/Delimiter.pm lib/PPIx/Regexp/Token/Greediness.pm lib/PPIx/Regexp/Token/GroupType.pm lib/PPIx/Regexp/Token/GroupType/Assertion.pm lib/PPIx/Regexp/Token/GroupType/BranchReset.pm lib/PPIx/Regexp/Token/GroupType/Code.pm lib/PPIx/Regexp/Token/GroupType/Modifier.pm lib/PPIx/Regexp/Token/GroupType/NamedCapture.pm lib/PPIx/Regexp/Token/GroupType/Script_Run.pm lib/PPIx/Regexp/Token/GroupType/Subexpression.pm lib/PPIx/Regexp/Token/GroupType/Switch.pm lib/PPIx/Regexp/Token/Interpolation.pm lib/PPIx/Regexp/Token/Literal.pm lib/PPIx/Regexp/Token/Modifier.pm lib/PPIx/Regexp/Token/NoOp.pm lib/PPIx/Regexp/Token/Operator.pm lib/PPIx/Regexp/Token/Quantifier.pm lib/PPIx/Regexp/Token/Recursion.pm lib/PPIx/Regexp/Token/Reference.pm lib/PPIx/Regexp/Token/Structure.pm lib/PPIx/Regexp/Token/Unknown.pm lib/PPIx/Regexp/Token/Unmatched.pm lib/PPIx/Regexp/Token/Whitespace.pm lib/PPIx/Regexp/Tokenizer.pm lib/PPIx/Regexp/Util.pm LICENSES/Artistic LICENSES/Copying Makefile.PL MANIFEST This list of files META.json META.yml README t/basic.t t/fuzz.t t/parse.t t/string.t t/string_unit.t t/unit.t t/version.t t/xplain.t xt/author/changes.t xt/author/critic.t xt/author/executable.t xt/author/kwalitee.t xt/author/manifest.t xt/author/minimum_perl.t xt/author/perlcriticrc xt/author/pod.t xt/author/pod_coverage.t xt/author/pod_spelling.t xt/author/unicode_short_charclass.t PPIx-Regexp-0.055/META.json000444000765000024 2364413237102475 14471 0ustar00tomstaff000000000000{ "abstract" : "Parse regular expressions", "author" : [ "Thomas R. Wyant, III F" ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4224", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "PPIx-Regexp", "no_index" : { "directory" : [ "inc", "t", "xt" ] }, "prereqs" : { "build" : { "requires" : { "Test::More" : "0.88" } }, "runtime" : { "requires" : { "Carp" : "0", "Exporter" : "0", "List::MoreUtils" : "0", "List::Util" : "0", "PPI::Document" : "1.117", "Scalar::Util" : "0", "Task::Weaken" : "0", "base" : "0", "constant" : "0", "perl" : "5.006", "strict" : "0", "warnings" : "0" } } }, "provides" : { "PPIx::Regexp" : { "file" : "lib/PPIx/Regexp.pm", "version" : "0.055" }, "PPIx::Regexp::Constant" : { "file" : "lib/PPIx/Regexp/Constant.pm", "version" : "0.055" }, "PPIx::Regexp::Dumper" : { "file" : "lib/PPIx/Regexp/Dumper.pm", "version" : "0.055" }, "PPIx::Regexp::Element" : { "file" : "lib/PPIx/Regexp/Element.pm", "version" : "0.055" }, "PPIx::Regexp::Lexer" : { "file" : "lib/PPIx/Regexp/Lexer.pm", "version" : "0.055" }, "PPIx::Regexp::Node" : { "file" : "lib/PPIx/Regexp/Node.pm", "version" : "0.055" }, "PPIx::Regexp::Node::Range" : { "file" : "lib/PPIx/Regexp/Node/Range.pm", "version" : "0.055" }, "PPIx::Regexp::Node::Unknown" : { "file" : "lib/PPIx/Regexp/Node/Unknown.pm", "version" : "0.055" }, "PPIx::Regexp::StringTokenizer" : { "file" : "lib/PPIx/Regexp/StringTokenizer.pm", "version" : "0.055" }, "PPIx::Regexp::Structure" : { "file" : "lib/PPIx/Regexp/Structure.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Assertion" : { "file" : "lib/PPIx/Regexp/Structure/Assertion.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::BranchReset" : { "file" : "lib/PPIx/Regexp/Structure/BranchReset.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Capture" : { "file" : "lib/PPIx/Regexp/Structure/Capture.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::CharClass" : { "file" : "lib/PPIx/Regexp/Structure/CharClass.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Code" : { "file" : "lib/PPIx/Regexp/Structure/Code.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Main" : { "file" : "lib/PPIx/Regexp/Structure/Main.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Modifier" : { "file" : "lib/PPIx/Regexp/Structure/Modifier.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::NamedCapture" : { "file" : "lib/PPIx/Regexp/Structure/NamedCapture.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Quantifier" : { "file" : "lib/PPIx/Regexp/Structure/Quantifier.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::RegexSet" : { "file" : "lib/PPIx/Regexp/Structure/RegexSet.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Regexp" : { "file" : "lib/PPIx/Regexp/Structure/Regexp.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Replacement" : { "file" : "lib/PPIx/Regexp/Structure/Replacement.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Subexpression" : { "file" : "lib/PPIx/Regexp/Structure/Subexpression.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Switch" : { "file" : "lib/PPIx/Regexp/Structure/Switch.pm", "version" : "0.055" }, "PPIx::Regexp::Structure::Unknown" : { "file" : "lib/PPIx/Regexp/Structure/Unknown.pm", "version" : "0.055" }, "PPIx::Regexp::Support" : { "file" : "lib/PPIx/Regexp/Support.pm", "version" : "0.055" }, "PPIx::Regexp::Token" : { "file" : "lib/PPIx/Regexp/Token.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Assertion" : { "file" : "lib/PPIx/Regexp/Token/Assertion.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Backreference" : { "file" : "lib/PPIx/Regexp/Token/Backreference.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Backtrack" : { "file" : "lib/PPIx/Regexp/Token/Backtrack.pm", "version" : "0.055" }, "PPIx::Regexp::Token::CharClass" : { "file" : "lib/PPIx/Regexp/Token/CharClass.pm", "version" : "0.055" }, "PPIx::Regexp::Token::CharClass::POSIX" : { "file" : "lib/PPIx/Regexp/Token/CharClass/POSIX.pm", "version" : "0.055" }, "PPIx::Regexp::Token::CharClass::POSIX::Unknown" : { "file" : "lib/PPIx/Regexp/Token/CharClass/POSIX/Unknown.pm", "version" : "0.055" }, "PPIx::Regexp::Token::CharClass::Simple" : { "file" : "lib/PPIx/Regexp/Token/CharClass/Simple.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Code" : { "file" : "lib/PPIx/Regexp/Token/Code.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Comment" : { "file" : "lib/PPIx/Regexp/Token/Comment.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Condition" : { "file" : "lib/PPIx/Regexp/Token/Condition.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Control" : { "file" : "lib/PPIx/Regexp/Token/Control.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Delimiter" : { "file" : "lib/PPIx/Regexp/Token/Delimiter.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Greediness" : { "file" : "lib/PPIx/Regexp/Token/Greediness.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType" : { "file" : "lib/PPIx/Regexp/Token/GroupType.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType::Assertion" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Assertion.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType::BranchReset" : { "file" : "lib/PPIx/Regexp/Token/GroupType/BranchReset.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType::Code" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Code.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType::Modifier" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Modifier.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType::NamedCapture" : { "file" : "lib/PPIx/Regexp/Token/GroupType/NamedCapture.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType::Subexpression" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Subexpression.pm", "version" : "0.055" }, "PPIx::Regexp::Token::GroupType::Switch" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Switch.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Interpolation" : { "file" : "lib/PPIx/Regexp/Token/Interpolation.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Literal" : { "file" : "lib/PPIx/Regexp/Token/Literal.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Modifier" : { "file" : "lib/PPIx/Regexp/Token/Modifier.pm", "version" : "0.055" }, "PPIx::Regexp::Token::NoOp" : { "file" : "lib/PPIx/Regexp/Token/NoOp.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Operator" : { "file" : "lib/PPIx/Regexp/Token/Operator.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Quantifier" : { "file" : "lib/PPIx/Regexp/Token/Quantifier.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Recursion" : { "file" : "lib/PPIx/Regexp/Token/Recursion.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Reference" : { "file" : "lib/PPIx/Regexp/Token/Reference.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Structure" : { "file" : "lib/PPIx/Regexp/Token/Structure.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Unknown" : { "file" : "lib/PPIx/Regexp/Token/Unknown.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Unmatched" : { "file" : "lib/PPIx/Regexp/Token/Unmatched.pm", "version" : "0.055" }, "PPIx::Regexp::Token::Whitespace" : { "file" : "lib/PPIx/Regexp/Token/Whitespace.pm", "version" : "0.055" }, "PPIx::Regexp::Tokenizer" : { "file" : "lib/PPIx/Regexp/Tokenizer.pm", "version" : "0.055" }, "PPIx::Regexp::Util" : { "file" : "lib/PPIx/Regexp/Util.pm", "version" : "0.055" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "wyant@cpan.org", "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp" }, "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "type" : "git", "url" : "git://github.com/trwyant/perl-PPIx-Regexp.git", "web" : "https://github.com/trwyant/perl-PPIx-Regexp" } }, "version" : "0.055", "x_serialization_backend" : "JSON::PP version 2.97001" } PPIx-Regexp-0.055/META.yml000444000765000024 1577013237102475 14322 0ustar00tomstaff000000000000--- abstract: 'Parse regular expressions' author: - 'Thomas R. Wyant, III F' build_requires: Test::More: '0.88' dynamic_config: 1 generated_by: 'Module::Build version 0.4224, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: PPIx-Regexp no_index: directory: - inc - t - xt provides: PPIx::Regexp: file: lib/PPIx/Regexp.pm version: '0.055' PPIx::Regexp::Constant: file: lib/PPIx/Regexp/Constant.pm version: '0.055' PPIx::Regexp::Dumper: file: lib/PPIx/Regexp/Dumper.pm version: '0.055' PPIx::Regexp::Element: file: lib/PPIx/Regexp/Element.pm version: '0.055' PPIx::Regexp::Lexer: file: lib/PPIx/Regexp/Lexer.pm version: '0.055' PPIx::Regexp::Node: file: lib/PPIx/Regexp/Node.pm version: '0.055' PPIx::Regexp::Node::Range: file: lib/PPIx/Regexp/Node/Range.pm version: '0.055' PPIx::Regexp::Node::Unknown: file: lib/PPIx/Regexp/Node/Unknown.pm version: '0.055' PPIx::Regexp::StringTokenizer: file: lib/PPIx/Regexp/StringTokenizer.pm version: '0.055' PPIx::Regexp::Structure: file: lib/PPIx/Regexp/Structure.pm version: '0.055' PPIx::Regexp::Structure::Assertion: file: lib/PPIx/Regexp/Structure/Assertion.pm version: '0.055' PPIx::Regexp::Structure::BranchReset: file: lib/PPIx/Regexp/Structure/BranchReset.pm version: '0.055' PPIx::Regexp::Structure::Capture: file: lib/PPIx/Regexp/Structure/Capture.pm version: '0.055' PPIx::Regexp::Structure::CharClass: file: lib/PPIx/Regexp/Structure/CharClass.pm version: '0.055' PPIx::Regexp::Structure::Code: file: lib/PPIx/Regexp/Structure/Code.pm version: '0.055' PPIx::Regexp::Structure::Main: file: lib/PPIx/Regexp/Structure/Main.pm version: '0.055' PPIx::Regexp::Structure::Modifier: file: lib/PPIx/Regexp/Structure/Modifier.pm version: '0.055' PPIx::Regexp::Structure::NamedCapture: file: lib/PPIx/Regexp/Structure/NamedCapture.pm version: '0.055' PPIx::Regexp::Structure::Quantifier: file: lib/PPIx/Regexp/Structure/Quantifier.pm version: '0.055' PPIx::Regexp::Structure::RegexSet: file: lib/PPIx/Regexp/Structure/RegexSet.pm version: '0.055' PPIx::Regexp::Structure::Regexp: file: lib/PPIx/Regexp/Structure/Regexp.pm version: '0.055' PPIx::Regexp::Structure::Replacement: file: lib/PPIx/Regexp/Structure/Replacement.pm version: '0.055' PPIx::Regexp::Structure::Subexpression: file: lib/PPIx/Regexp/Structure/Subexpression.pm version: '0.055' PPIx::Regexp::Structure::Switch: file: lib/PPIx/Regexp/Structure/Switch.pm version: '0.055' PPIx::Regexp::Structure::Unknown: file: lib/PPIx/Regexp/Structure/Unknown.pm version: '0.055' PPIx::Regexp::Support: file: lib/PPIx/Regexp/Support.pm version: '0.055' PPIx::Regexp::Token: file: lib/PPIx/Regexp/Token.pm version: '0.055' PPIx::Regexp::Token::Assertion: file: lib/PPIx/Regexp/Token/Assertion.pm version: '0.055' PPIx::Regexp::Token::Backreference: file: lib/PPIx/Regexp/Token/Backreference.pm version: '0.055' PPIx::Regexp::Token::Backtrack: file: lib/PPIx/Regexp/Token/Backtrack.pm version: '0.055' PPIx::Regexp::Token::CharClass: file: lib/PPIx/Regexp/Token/CharClass.pm version: '0.055' PPIx::Regexp::Token::CharClass::POSIX: file: lib/PPIx/Regexp/Token/CharClass/POSIX.pm version: '0.055' PPIx::Regexp::Token::CharClass::POSIX::Unknown: file: lib/PPIx/Regexp/Token/CharClass/POSIX/Unknown.pm version: '0.055' PPIx::Regexp::Token::CharClass::Simple: file: lib/PPIx/Regexp/Token/CharClass/Simple.pm version: '0.055' PPIx::Regexp::Token::Code: file: lib/PPIx/Regexp/Token/Code.pm version: '0.055' PPIx::Regexp::Token::Comment: file: lib/PPIx/Regexp/Token/Comment.pm version: '0.055' PPIx::Regexp::Token::Condition: file: lib/PPIx/Regexp/Token/Condition.pm version: '0.055' PPIx::Regexp::Token::Control: file: lib/PPIx/Regexp/Token/Control.pm version: '0.055' PPIx::Regexp::Token::Delimiter: file: lib/PPIx/Regexp/Token/Delimiter.pm version: '0.055' PPIx::Regexp::Token::Greediness: file: lib/PPIx/Regexp/Token/Greediness.pm version: '0.055' PPIx::Regexp::Token::GroupType: file: lib/PPIx/Regexp/Token/GroupType.pm version: '0.055' PPIx::Regexp::Token::GroupType::Assertion: file: lib/PPIx/Regexp/Token/GroupType/Assertion.pm version: '0.055' PPIx::Regexp::Token::GroupType::BranchReset: file: lib/PPIx/Regexp/Token/GroupType/BranchReset.pm version: '0.055' PPIx::Regexp::Token::GroupType::Code: file: lib/PPIx/Regexp/Token/GroupType/Code.pm version: '0.055' PPIx::Regexp::Token::GroupType::Modifier: file: lib/PPIx/Regexp/Token/GroupType/Modifier.pm version: '0.055' PPIx::Regexp::Token::GroupType::NamedCapture: file: lib/PPIx/Regexp/Token/GroupType/NamedCapture.pm version: '0.055' PPIx::Regexp::Token::GroupType::Subexpression: file: lib/PPIx/Regexp/Token/GroupType/Subexpression.pm version: '0.055' PPIx::Regexp::Token::GroupType::Switch: file: lib/PPIx/Regexp/Token/GroupType/Switch.pm version: '0.055' PPIx::Regexp::Token::Interpolation: file: lib/PPIx/Regexp/Token/Interpolation.pm version: '0.055' PPIx::Regexp::Token::Literal: file: lib/PPIx/Regexp/Token/Literal.pm version: '0.055' PPIx::Regexp::Token::Modifier: file: lib/PPIx/Regexp/Token/Modifier.pm version: '0.055' PPIx::Regexp::Token::NoOp: file: lib/PPIx/Regexp/Token/NoOp.pm version: '0.055' PPIx::Regexp::Token::Operator: file: lib/PPIx/Regexp/Token/Operator.pm version: '0.055' PPIx::Regexp::Token::Quantifier: file: lib/PPIx/Regexp/Token/Quantifier.pm version: '0.055' PPIx::Regexp::Token::Recursion: file: lib/PPIx/Regexp/Token/Recursion.pm version: '0.055' PPIx::Regexp::Token::Reference: file: lib/PPIx/Regexp/Token/Reference.pm version: '0.055' PPIx::Regexp::Token::Structure: file: lib/PPIx/Regexp/Token/Structure.pm version: '0.055' PPIx::Regexp::Token::Unknown: file: lib/PPIx/Regexp/Token/Unknown.pm version: '0.055' PPIx::Regexp::Token::Unmatched: file: lib/PPIx/Regexp/Token/Unmatched.pm version: '0.055' PPIx::Regexp::Token::Whitespace: file: lib/PPIx/Regexp/Token/Whitespace.pm version: '0.055' PPIx::Regexp::Tokenizer: file: lib/PPIx/Regexp/Tokenizer.pm version: '0.055' PPIx::Regexp::Util: file: lib/PPIx/Regexp/Util.pm version: '0.055' requires: Carp: '0' Exporter: '0' List::MoreUtils: '0' List::Util: '0' PPI::Document: '1.117' Scalar::Util: '0' Task::Weaken: '0' base: '0' constant: '0' perl: '5.006' strict: '0' warnings: '0' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp license: http://dev.perl.org/licenses/ repository: git://github.com/trwyant/perl-PPIx-Regexp.git version: '0.055' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' PPIx-Regexp-0.055/Makefile.PL000444000765000024 255113237102475 14774 0ustar00tomstaff000000000000use strict; use warnings; use lib qw{ inc }; use ExtUtils::MakeMaker; use My::Module::Meta; (my $mmv = ExtUtils::MakeMaker->VERSION) =~ s/_//g; my $meta = My::Module::Meta->new(); my %args = ( NAME => 'PPIx::Regexp', VERSION_FROM => 'lib/PPIx/Regexp.pm', PREREQ_PM => $meta->requires(), PL_FILES => {}, # Prevent old MakeMaker from running Build.PL 'dist' => {COMPRESS => 'gzip', SUFFIX => 'gz'}, AUTHOR => 'Thomas R. Wyant, III F', ABSTRACT => 'Parse regular expressions', realclean => { FILES => 'cover_db' }, ); $mmv >= 6.31 and $args{LICENSE} = 'perl'; $mmv >= 6.4501 and $args{META_MERGE} = $meta->meta_merge( $meta->provides(), ); $mmv >= 6.4701 and $args{MIN_PERL_VERSION} = $meta->requires_perl(); $mmv >= 6.5501 and $args{BUILD_REQUIRES} = $meta->build_requires() or $mmv >= 6.4501 and $args{META_MERGE}{build_requires} = $meta->build_requires(); WriteMakefile (%args); sub MY::postamble { my ( $self, @args ) = @_; my $authortest = $self->test_via_harness( '$(FULLPERLRUN)', '$(AUTHORTEST_FILES)' ); $authortest =~ s/ \s+ \z //smx; $authortest =~ s/ \A \s+ //smx; chomp $authortest; return <<"EOD"; AUTHORTEST_FILES = t/*.t xt/author/*.t authortest :: pure_all AUTHOR_TESTING=1 $authortest testcover :: pure_all cover -test EOD } # ex: set textwidth=72 : PPIx-Regexp-0.055/README000444000765000024 321413237102475 13677 0ustar00tomstaff000000000000PPIx-Regexp is Copyright (C) 2009-2018 by Thomas R. Wyant, III DESCRIPTION This package parses regular expressions as they appear in Perl scripts, generating a structure similar to the structure generated by PPI when it parses a Perl script, and navigable in much the same way. The PPIx::Regexp object is instantiated using either new() or new_from_cache(). Either way, you must pass it a regular expression, either as a string or as one of the three relevant PPI objects: PPI::Token::StringLike::Regexp, PPI::Token::Regexp::Match, or PPI::Token::Regexp::Substitute. In the case of new_from_cache(), only one PPIx::Regexp object will be generated from a given PPI object; subsequent calls with the same PPI object will return the same PPIx::Regexp object. See the eg directory for samples. INSTALLATION This module is installable by either of the two usual incantations: tar -xzf PPIx-Regexp-9.999.tar.gz cd PPIx-Regexp-9.999 perl Makefile.PL make make test sudo make install or tar -xzf PPIx-Regexp-9.999.tar.gz cd PPIx-Regexp-9.999 perl Build.PL ./Build ./Build test sudo ./Build install Of course, since it is pure Perl, in desperation you can simply drop the files from the lib directory of the distribution into the appropriate @INC directory. LICENSING INFORMATION This package is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. PPIx-Regexp-0.055/LICENSES000755000765000024 013237102475 14067 5ustar00tomstaff000000000000PPIx-Regexp-0.055/LICENSES/Artistic000444000765000024 1373713237102475 15764 0ustar00tomstaff000000000000 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 as specified below. "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 uunet.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) give non-standard executables non-standard names, and clearly document 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. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 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 whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. 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 PPIx-Regexp-0.055/LICENSES/Copying000444000765000024 3053013237102475 15600 0ustar00tomstaff000000000000 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our 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. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, 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 a 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 tell them 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. 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 Agreement 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 work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 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 General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual 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 General Public License. d) 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. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 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 Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying 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. 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. 7. 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 the 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 the license, you may choose any version ever published by the Free Software Foundation. 8. 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 9. 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. 10. 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 Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! PPIx-Regexp-0.055/eg000755000765000024 013237102475 13255 5ustar00tomstaff000000000000PPIx-Regexp-0.055/eg/README000444000765000024 252413237102475 14275 0ustar00tomstaff000000000000This directory contains example scripts using PPIx::Regexp. Specifically: README - is this file. interpolated - is a script that takes as its arguments a list of files and/or directories, and lists all Perl regular expressions which interpolate. If the -once option is asserted, only those expressions which interpolate and do not have the /o modifier are listed. preaccepts - is a script that takes as its arguments a Perl regular expression and one or more Perl version numbers. For each Perl version number, it displays whether that version of Perl considers the regular expression to be valid. predump - is a script that takes as its argument a regular expression, and dumps the parse tree. Various command options are available to control the dump. The -help option gets you complete documentation of the script. prenav - is a script that takes as its single argument a regular expression. The user can then interactively navigate around the parse tree. The 'help' command gives help. preslurp - is a script that makes files into PPI::Document objects, then extracts the regular expression tokens from the documents and dumps them. Various command options are available to control the dump. The -help option gets you complete documentation of the script. # ex: set textwidth=72 autoindent : PPIx-Regexp-0.055/eg/interpolated000555000765000024 544213237102475 16037 0ustar00tomstaff000000000000#!/usr/local/bin/perl use 5.006; use strict; use warnings; use File::Find; use File::Spec; use Getopt::Long; use PPI; use PPIx::Regexp; my %opt; GetOptions( \%opt, qw{ once! } ) or die; find( \&interpolated, @ARGV ? @ARGV : ( File::Spec->curdir() ) ); sub interpolated { -d $_ and return prune(); is_perl( $_ ) or return; my $named; my $doc = PPI::Document->new( $_ ); foreach my $class ( qw{ PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute PPI::Token::QuoteLike::Regexp } ) { foreach my $elem ( @{ $doc->find( $class ) || [] } ) { my $re = PPIx::Regexp->new( $elem ); $re->regular_expression()->find_first( 'PPIx::Regexp::Token::Interpolation' ) or next; $opt{once} and $re->modifier()->asserts( 'o' ) and next; $named++ or print $File::Find::name, "\n"; print ' ', $re->content(), "\n"; } } } sub is_perl { my ( $fn ) = @_; -T $fn or return; $fn =~ m/ [.] pm \z /smx and return 1; $fn =~ m/ [.] pl \z /smxi and return 1; open ( my $fh, '<', $fn ) or return; local $_ = <$fh>; close $fh; defined $_ or return; m/ \A [#] ! .*? perl /smx and return 1; m/ \A [#] ! /smx and return; $fn =~ m/ [.] t \z /smx and return 1; return; } { my %pruned; BEGIN { %pruned = map { $_ => 1 } qw{ blib }; } sub prune { '.' eq $_ and return; $pruned{$_} or m/ \A [.] /smx or return; $File::Find::prune = 1; return; } } __END__ =head1 TITLE interpolated - Find all interpolated regular expressions =head1 SYNOPSIS interpolated interpolated lib interpolated -once =head1 OPTIONS =over =item -once If this option is asserted, only interpolated regular expressions B the C qualifier are found. =head1 DETAILS This script searches files or directories for interpolated regular expressions. These are considered to be matches or C expressions containing interpolations, or substitutions containing interpolations in their regular expressions. Interpolation in the replacement portion of the substitution are not considered. The names of any files containing such regular expressions are listed, along with the statements themselves. If C<-once> is asserted, only regular expressions without the C modifier are listed. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2010-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/eg/preaccepts000555000765000024 351713237102475 15477 0ustar00tomstaff000000000000#!/usr/bin/env perl use 5.006; use strict; use warnings; use Getopt::Long 2.33 qw{ :config auto_version }; use Pod::Usage; use PPIx::Regexp; our $VERSION = '0.055'; my %opt; GetOptions( \%opt, help => sub { pod2usage( { -verbose => 2 } ) }, ) and @ARGV > 1 or pod2usage( { -verbose => 0 } ); my $pre = PPIx::Regexp->new( my $regexp = shift @ARGV ); foreach my $perl ( @ARGV ) { print $regexp, ( $pre->accepts_perl( $perl ) ? ' is' : ' is not' ), " accepted by $perl\n"; } __END__ =head1 TITLE preaccepts - See whether specified versions of Perl accept a given regular expression =head1 SYNOPSIS preaccepts '/x{' 5.025 5.025001 5.026 5.027 5.027001 preaccepts -help preaccepts -version =head1 OPTIONS =head2 -help This option displays the documentation for this script. The script then exits. =head2 -version This option displays the version of this script. The script then exits. =head1 DETAILS This Perl script accepts as its first argument a Perl regular expression, and as its second and subsequent arguments Perl verions numbers. It displays to standard out whether or not each given version of Perl considers the specified regular expression to be correct. The heavy lifting for this is done by the L L method. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2017-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/eg/predump000555000765000024 2272713237102475 15046 0ustar00tomstaff000000000000#!/usr/local/bin/perl use 5.006; use strict; use warnings; use Getopt::Long 2.33; use Pod::Usage; use PPI::Document; use PPIx::Regexp::Dumper; use Scalar::Util qw{ refaddr }; use vars qw{ $VERSION }; $VERSION = '0.055'; my %opt = ( default_modifiers => [], verbose => 0, ); GetOptions( \%opt, help => sub { pod2usage ( { -exitval => 0, -verbose => 2, -output => \*STDOUT, } ) }, 'guess!' => \&set_parse, 'regex!' => \&set_parse, 'string!' => \&set_parse, qw{ default_modifiers|default-modifiers=s@ encoding=s explain! files! indent=i margin=i objectify! ordinal! perl_version! postderef! significant! strict! test! tokens! trace+ unescape! verbose+ } ) and @ARGV or pod2usage( { -exitval => 2, -verbose => 1, -output => \*STDERR, } ); $opt{default_modifiers} = [ map { split qr{ \s* , \s* }smx } @{ $opt{default_modifiers} } ]; foreach my $re ( process_args( \%opt, @ARGV ) ) { if ( ! $opt{test} ) { my @output = ( "\n$re" ); @{ $opt{default_modifiers} } and push @output, q{default_modifiers => '} . join( ',', @{ $opt{default_modifiers} } ) . q{'}; print join( "\t", @output ), "\n"; @output = item_info( $re ) and print join( "\t", @output ), "\n"; } PPIx::Regexp::Dumper->new( $re, %opt )->print(); } { my @docs; # Have to save reference my %file; sub process_args { my ( $opt, @args ) = @_; my @rslt; foreach my $datum ( @args ) { if ( $opt->{files} ) { my $doc = PPI::Document->new( $datum, readonly => 1 ) or die "Can not make PPI::Document from file '$datum'\n"; $doc->index_locations(); push @docs, $doc; push @rslt, extract_res( $doc, $opt ); $file{ refaddr( $doc ) } = { name => $datum, }; } else { $opt->{unescape} and $datum =~ s/ \\\\ /\\/smxg; if ( $opt->{objectify} ) { my $doc = PPI::Document->new( \$datum ) or die "Can not make PPI::Document from '$datum'\n"; push @docs, $doc; push @rslt, extract_res( $doc, $opt ); } else { push @rslt, $datum; } } } delete $opt->{files}; delete $opt->{objectify}; delete $opt->{unescape}; return @rslt; } sub item_info { my ( $obj ) = @_; ref $obj or return; eval { $obj->isa( 'PPI::Element' ); } or return; my $doc = $obj->document() or return; my $info = $file{ refaddr $doc } or return; return wantarray ? ( $info->{name}, @{ $obj->location() || [] }[0, 2] ) : $info->{name}; } } { my ( %classes, @regex, @string ); BEGIN { @regex = qw{ PPI::Token::QuoteLike::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute }; @string = qw{ PPI::Token::Quote PPI::Token::QuoteLike::Command PPI::Token::QuoteLike::BackTick PPI::Token::HereDoc }; %classes = ( guess => [ @regex, @string ], regex => \@regex, string => \@string, ); } sub extract_res { my ( $doc, $opt ) = @_; my $parse = $opt->{parse} || 'regex'; return ( map { @{ $doc->find( $_ ) || [] } } @{ $classes{$parse} || $classes{regex} } ); } } sub set_parse { my ( $opt, $assert ) = @_; if ( $assert ) { $opt{parse} = "$opt"; } else { delete $opt{parse}; } return; } __END__ =head1 NAME predump - Dump a regular expression =head1 SYNOPSIS predump 'qr{foo}smx' predump -ordinal 'm/foo/x' You can use predump -help for full documentation on usage. =head1 DESCRIPTION This Perl script parses the regular expression given on its command line and dumps the results of the parse to standard out. The following options are recognized: =over =item -default-modifiers text This option specifies default modifiers for the regular expression. You can specify more than one, either as a comma-separated list or by specifying the option multiple times, or both. It is simply passed through to L<< PPIx::Regexp->new()|PPIx::Regexp/new >>. This option can also be expressed as C<-default_modifiers>. =item -encoding name This option specifies the encoding of the regular expression. It is simply passed through to L<< PPIx::Regexp->new()|PPIx::Regexp/new >>. =item -files If true, this option specifies that the arguments are files whose regular expressions are to be analyzed. If this options is asserted, C<-objectify> and C<-unescape> are ignored. =item -guess If true, this option specifies that the parser guess whether the argument is to be parsed as a regex or a string. If false, it specifies the default parse, which is as a regex. If more than one of C<-guess>, C<-regex> and C<-string> is specified, the last one parsed (normally the C<-string> are specified, the last specification parsed (normally the rightmost one) wins. The default is C<-noguess>, which specifies the default parse. =item -indent number This option specifies the number of spaces to indent each level of the parse hierarchy. It is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =item -margin number This option specifies the width of the left margin of the dump output. It is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =item -objectify If true, this option specifies that the arguments should be made into L objects before being passed to PPIx::Regexp. This option is ignored if C<-files> is asserted. =item -ordinal If true, this option specifies that the ordinal value of all L objects be displayed as part of the dump. The default is false. This is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =item -perl_version If true, this option specifies that the dump include the perl version applicable to each dumped item. The default is false. This is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =item -postderef If true, this option specifies that postfix dereferences are recognized in code and interpolations. If false (specified as C<-nopostderef>) they are not recognized. For the default see the documentation for the tokenizer's L method. =item -regex If true, this option specifies that the parser parse the argument as a regex. If false, it specifies the default parse, which is as a regex, so this option is unnecessary unless the default parse changes. If more than one of C<-guess>, C<-regex> and C<-string> is specified, the last one parsed (normally the C<-string> are specified, the last specification parsed (normally the rightmost one) wins. The default is C<-noregex>, which specifies the default parse. =item -significant If true, this option specifies that the dump include only significant syntax elements. That is, no comments or non-significant white space. The default is false. This is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =item -string If true, this option specifies that the argument be parsed as a string, not a regex. If false, it specifies the default parse, which is as a regex. If more than one of C<-guess>, C<-regex> and C<-string> is specified, the last one parsed (normally the C<-string> are specified, the last specification parsed (normally the rightmost one) wins. The default is C<-nostring>, which specifies the default parse. =item -test If true, this option specifies that the dump take the form of a predefined set of tests be generated for the regular expression. This option is unsupported in the sense that the author makes no commitment to what it will do, and reserves the right to change it without notice. This is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =item -tokens If true, this option specifies that only tokenization be done on the regular expression, and the output tokens dumped to standard out. This is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =item -trace If true, this option specifies the generation of trace output from the parse. It is unsupported in the sense that the author makes no commitment to what it will do, and reserves the right to change it without notice. This is simply passed through to L<< PPIx::Regexp->new()|PPIx::Regexp/new >>. =item -unescape If true, this option causes the argument to be unescaped before processing. You would use it if the argument is a Perl single-quotish string, since Perl's single-quoted syntax differs from that of the usual Unix shell. This option is ignored if C<-files> is asserted. =item -verbose If true, this option causes more information to be dumped about each object produced by the parse. It is unsupported in the sense that the author makes no commitment to what it will do, and reserves the right to change it without notice. This is simply passed through to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new >>. =back =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/eg/prenav000555000765000024 1333113237102475 14654 0ustar00tomstaff000000000000#!/usr/local/bin/perl use strict; use warnings; use Pod::Usage; use PPIx::Regexp; use PPIx::Regexp::Dumper; use PPIx::Regexp::Util qw{ __instance }; use Term::ReadLine; @ARGV or die "Need an argument.\n"; my $re = PPIx::Regexp->new( $ARGV[0] ) or die PPIx::Regexp->errmsg(); my $obj = $re; my $tr = Term::ReadLine->new( 'Navigate a regular expression' ); my %internal = ( capture_names => sub { defined $obj or return; return join( ', ', map { "'$_'" } $obj->capture_names() ); }, delimiters => sub { defined $obj or return; return join( ', ', map { "'$_'" } $obj->delimiters() ); }, dump => sub { my @args; defined $_[0] and @args = split qr{ \s+ }smx, $_[0]; return PPIx::Regexp::Dumper->new( $obj, @args )->string(); }, help => sub { pod2usage( { -exitval => 'NOEXIT', -verbose => 2, -output => \*STDOUT, } ); return; }, nav => sub { return _safe( $obj->nav() ); }, parse => sub { my $temp = PPIx::Regexp->new( $_[0] ) or return PPIx::Regexp->errstr(); return ( $obj = $re = $temp ); }, reset => sub { return ( $obj = $re ); }, ); sub _safe { my ( @args ) = @_; my $rslt = join ', ', map { ref $_ eq 'ARRAY' ? '[ ' . _safe( @{ $_ } ) . ' ]' : "'$_'" } @args; $rslt =~ s/ \[ \s+ \] /[]/smxg; $rslt =~ s/ ' ( \d+ ) ' /$1/smxg; $rslt =~ s/ \[ \s* ( \d+ ) \s* \] /$1/smxg; $rslt =~ s/ ' ( \w+ ) ', /$1 =>/smxg; return $rslt; } while ( defined ( my $buffer = $tr->readline( 'prenav> ' ) ) ) { $buffer =~ s/ \s+ \z //smx; $buffer or next; $buffer =~ s/ \A \s+ //smx; '#' eq substr $buffer, 0, 1 and next; my ( $method, $arg ) = split qr{\s+}smx, $buffer, 2; 'exit' eq $method and last; my $temp = eval { $internal{$method} ? $internal{$method}->( $arg ) : $obj->$method( $arg ); } or do { if ( $@ ) { warn $@; } else { print "undef\n"; } next; }; print _format( $temp ); __instance( $temp, 'PPIx::Regexp::Element' ) and $obj = $temp; } sub _format { my ( @args ) = @_; my $rslt; foreach my $thing ( @args ) { if ( __instance( $thing, 'PPIx::Regexp::Element' ) ) { $rslt .= $thing->class() . "\t" . $thing->content() . "\n"; } elsif ( ref $thing eq 'ARRAY' ) { $rslt .= _format( @{ $thing } ); } else { $rslt .= $thing =~ m/ \n /smx ? $thing : $thing =~ m/ \A ' /smx ? "$thing\n" : $thing =~ m/ \D /smx ? "'$thing'\n" : "$thing\n"; } } return $rslt; } __END__ =head1 NAME prenav - Navigate a PPIx::Regexp parse tree =head1 SYNOPSIS prenav 's/(\w+)/\u$1/g' prenav> find_first Token::CharClass::Simple PPIx::Regexp::Token::CharClass::Simple \w prenav> dump verbose 1 PPIx::Regexp::Token::CharClass::Simple '\\w' significant can_be_quantified prenav> parent PPIx::Regexp::Structure::Capture (\w+) prenav> exit =head1 DESCRIPTION This script takes as its argument a string to be parsed as a regular expression, and prompts the user for navigation commands. A navigation command is any method that returns another element in the parse tree. Unless documented otherwise, all commands apply to the current object. Initially the current object is the L object generated by the parse. Once a navigation command is issued, the object navigated to becomes the current object. If the navigation command does not specify an object (e.g. C when the current object has fewer than 5 children) the current object remains unchanged. In addition to the navigation methods, any method that returns a scalar value can be used as a command. The value returned will be displayed. In addition to all the above, the following commands are recognized: =over =item capture_names This command wraps the L<< PPIx::Regexp->capture_names()|PPIx::Regexp/capture_names >> method, joining the results into a comma-delimited string. =item dump This command dumps the current object. Options to L<< PPIx::Regexp::Dumper->new()|PPIx::Regexp::Dumper/new> may be specified as arguments to the command. See the L for an example. =item exit This comamnd terminates the script. =item help This command displays this documentation. =item nav nav This command displays the method calls and arguments needed to navigate from the root of the parse tree to the current object. Yes, this is a perfectly good method, but we wrap the results of that method in some semi-nice formatting. Any arguments are ignored =item parse parse s/ ( \w+ ) foo \1 /bar/smx This command provides another regular expression to parse. If the parse succeeds, the previous regular expression is abandoned, and the new L object becomes the current object. The new regular expression is taken to be everything on the line after the whit espace after the word C. It should B be quoted. =item reset This command selects the top-level object as the current object. The C command does the same thing, but C does it by running through the parent chain, where C simply slam-dunks the retained L object. =back =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/eg/preslurp000555000765000024 1633613237102475 15245 0ustar00tomstaff000000000000#!/usr/bin/env perl use strict; use warnings; use Cwd qw{ abs_path getcwd }; use File::Find; use File::Temp; use Getopt::Long 2.33 qw{ :config auto_version }; use IO::File; use Pod::Usage; use PPI::Document; use PPIx::Regexp; use PPIx::Regexp::Dumper; use PPIx::Regexp::Tokenizer; our $VERSION = '0.055'; my %opt = ( verbose => 0, ); our $BASE = getcwd(); our @PREFIX; GetOptions( \%opt, qw{ archive! encoding=s failures! ignore=s include! ordinal! recurse! significant! tokens! verbose+ }, help => sub { pod2usage( { -verbose => 2 } ) }, ) or pod2usage( { -verbose => 0 } ); if ( $opt{archive} ) { require Archive::Any; } my @ignore; if ( $opt{ignore} ) { my $fh = IO::File->new( $opt{ignore}, '<' ) or die "Unable to open $opt{ignore}: $!\n"; while ( <$fh> ) { s/ \s+ \z //smx; $_ or next; s/ \A \s+ //smx; '#' eq substr $_, 0, 1 and next; push @ignore, qr{$_}smx; } close $fh; } my %dumper_opt = ( encoding => $opt{encoding}, margin => 4, ordinal => $opt{ordinal}, significant => $opt{significant}, verbose => $opt{verbose}, ); my $parser = $opt{tokens} ? 'PPIx::Regexp::Tokenizer' : 'PPIx::Regexp'; if ( $opt{include} ) { push @ARGV, @INC; $opt{recurse} = 1; } $opt{recurse} ||= $opt{archive}; if ( $opt{recurse} ) { @ARGV or push @ARGV, File::Spec->curdir(); find( { no_chdir => 1, wanted => sub { foreach my $re ( @ignore ) { $File::Find::name =~ $re and return; } handle_perl( $_ ) || handle_archive( $_ ); }, }, @ARGV ); } else { foreach ( @ARGV ) { -T $_ && slurp( $_ ); } } sub handle_archive { my ( $fn ) = @_; $opt{archive} or return; -f $fn or return; -T $fn and return; $fn =~ m/ [.] (?: gz | bz2 | zip | tgz | tar ) \z /smx or return; $opt{verbose} and warn "$fn\n"; my $arch = Archive::Any->new( $fn ) or return; $arch->is_naughty() and do { warn "$fn is naughty. Skipping.\n"; return; }; $arch->is_impolite() and do { warn "$fn is impolite. Skipping.\n"; return; }; my $dir = File::Temp->newdir(); eval { $arch->extract( $dir ); 1; } or do { warn "Extract from $fn failed.\n"; }; local @PREFIX = File::Spec->abs2rel( $fn ); local $BASE = $dir; find( { no_chdir => 1, wanted => sub { foreach my $re ( @ignore ) { $File::Find::name =~ $re and return; } handle_perl( $_ ) } }, $dir ); return 1; } sub handle_perl { my ( $fn ) = @_; is_perl( $fn ) or return; $opt{verbose} and warn "$fn\n"; slurp( $fn ); return 1; } sub is_perl { my ( $fn ) = @_; -T $fn or return; $fn =~ m/ [.] pm \z /smx and return 1; $fn =~ m/ [.] pl \z /smxi and return 1; open ( my $fh, '<', $fn ) or return; local $_ = <$fh>; close $fh; defined $_ or return; m/ \A [#] ! .*? perl /smx and return 1; m/ \A [#] ! /smx and return; $fn =~ m/ [.] t \z /smx and return 1; return; } sub slurp { my ( $fn ) = @_; my $doc = PPI::Document->new( $fn ) or do { warn "Unable to make a PPI::Document from $fn: ", PPI::Document->errstr; return; }; my @found; foreach my $class ( qw{ PPI::Token::QuoteLike::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute } ) { foreach my $token ( @{ $doc->find( $class ) || [] } ) { my $display = !$opt{failures}; my @regex = ( $token ); if ( my $re = $parser->new( $token, encoding => $opt{encoding} ) ) { if ( $re->isa( 'PPIx::Regexp::Tokenizer' ) ) { push @regex, [ $re->tokens() ]; } else { push @regex, $re; } $display ||= $re->failures(); } else { $display = 1; push @regex, $token->class(), ' not handled'; } $display and push @found, \@regex; } } if ( @found ) { print "\n", join( ' ', @PREFIX, $fn ), "\n"; foreach ( @found ) { my ( $thing, $content ) = @{ $_ }; print ' ', $thing->class(), "\t", $thing->content(), "\n"; my $dmp = PPIx::Regexp::Dumper->new( $content, %dumper_opt ); $dmp->print(); } } return; } __END__ =head1 NAME preslurp - Analyze the regular expressions in a bunch of files =head1 SYNOPSIS preslurp -recurse . For full details on usage, use preslurp -help =head1 DETAILS This script makes L objects out of files it deems are Perl, then does a L dump on all L, L and L objects it finds. The following options control its use: =over =item -archive If this option is asserted, it specifies that any archive files found should be expanded and their contents searched. This option implies C<-recurse>. This option is only available if L is installed. =item -encoding name This option specifies the encoding of the files. It is passed directly to L and L. =item -failures If this option is asserted, only regular expressions with parse failures are reported. =item -help If this option is asserted, this documentation is displayed and the script exits. =item -ignore filename This option specifies the name of a file containing a list of files to ignore. The files are specified as regular expressions, listed one per line. Blank lines and lines beginning with '#' are ignored. =item -include If this option is asserted, it specifies that the contents of C<@INC> be added to the files to be checked. It also causes -recurse to be asserted. =item -ordinal If this option is asserted, it specifies that the ordinal value of any L objects be displayed in the dump. In reality, this option is simply passed to L. =item -recurse If this option is specified, this script recurses into any directories found. =item -significant If this option is asserted, only significant C objects are dumped. In reality, this option is simply passed to L. =item -tokens If this option is asserted, only L objects are dumped. In reality, this option is simply passed to L. =item -verbose If this option is asserted, you get a more verbose dump, though what that means is undocumented. In reality, this option is simply passed to L. =back =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/inc000755000765000024 013237102475 13433 5ustar00tomstaff000000000000PPIx-Regexp-0.055/inc/My000755000765000024 013237102475 14020 5ustar00tomstaff000000000000PPIx-Regexp-0.055/inc/My/Module000755000765000024 013237102475 15245 5ustar00tomstaff000000000000PPIx-Regexp-0.055/inc/My/Module/Build.pm000444000765000024 400313237102475 16774 0ustar00tomstaff000000000000package My::Module::Build; use strict; use warnings; use Module::Build; our @ISA = qw{ Module::Build }; our $VERSION = '0.055'; use Carp; sub ACTION_authortest { my ( $self ) = @_; # @args unused local $ENV{AUTHOR_TESTING} = 1; $self->depends_on( 'build' ); $self->test_files( qw{ t xt/author } ); $self->depends_on( 'test' ); return; } 1; __END__ =head1 NAME My::Module::Build - Extend Module::Build for PPIx::Regexp =head1 SYNOPSIS perl Build.PL ./Build ./Build test ./Build authortest # supplied by this module ./Build install =head1 DESCRIPTION This extension of L adds the following action to those provided by L: authortest =head1 ACTIONS This module provides the following action: =over =item authortest This action runs not only those tests which appear in the F directory, but those that appear in the F directory. The F tests are provided for information only, since some of them (notably F and F) are very sensitive to the configuration under which they run. Some of the F tests require modules that are not named as requirements. These should disable themselves if the required modules are not present. This test is sensitive to the C argument, but not to the C<--test_files> argument. =back =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/inc/My/Module/Meta.pm000444000765000024 1211313237102475 16644 0ustar00tomstaff000000000000package My::Module::Meta; use 5.006; use strict; use warnings; use Carp; sub new { my ( $class ) = @_; ref $class and $class = ref $class; my $self = { distribution => $ENV{MAKING_MODULE_DISTRIBUTION}, }; bless $self, $class; return $self; } sub build_requires { return +{ 'Test::More' => 0.88, # Because of done_testing(). }; } sub distribution { my ( $self ) = @_; return $self->{distribution}; } sub meta_merge { my ( undef, @extra ) = @_; return { 'meta-spec' => { version => 2, }, no_index => { directory => [ qw{ inc t xt } ], }, resources => { bugtracker => { web => 'https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp', mailto => 'wyant@cpan.org', }, license => 'http://dev.perl.org/licenses/', repository => { type => 'git', url => 'git://github.com/trwyant/perl-PPIx-Regexp.git', web => 'https://github.com/trwyant/perl-PPIx-Regexp', }, }, @extra, }; } sub provides { -d 'lib' or return; local $@ = undef; my $provides = eval { require Module::Metadata; Module::Metadata->provides( version => 2, dir => 'lib' ); } or return; return ( provides => $provides ); } sub requires { my ( undef, @extra ) = @_; # Invocant unused ## if ( ! $self->distribution() ) { ## } return { 'Carp' => 0, 'Exporter' => 0, 'List::MoreUtils' => 0, 'List::Util' => 0, 'PPI::Document' => 1.117, # for new( readonly => 1 ) 'Scalar::Util' => 0, 'Task::Weaken' => 0, 'base' => 0, 'constant' => 0, 'strict' => 0, 'warnings' => 0, @extra, }; } sub requires_perl { return 5.006; } 1; __END__ =head1 NAME My::Module::Meta - Information needed to build PPIx::Regexp =head1 SYNOPSIS use lib qw{ inc }; use My::Module::Meta; my $meta = My::Module::Meta->new(); use YAML; print "Required modules:\n", Dump( $meta->requires() ); =head1 DETAILS This module centralizes information needed to build C. It is private to the C package, and may be changed or retracted without notice. =head1 METHODS This class supports the following public methods: =head2 new my $meta = PPIx::Meta->new(); This method instantiates the class. =head2 build_requires use YAML; print Dump( $meta->build_requires() ); This method computes and returns a reference to a hash describing the modules required to build the C package, suitable for use in a F C key, or a F C<< {META_MERGE}->{build_requires} >> or C key. =head2 distribution if ( $meta->distribution() ) { print "Making distribution\n"; } else { print "Not making distribution\n"; } This method returns the value of the environment variable C at the time the object was instantiated. =head2 meta_merge use YAML; print Dump( $meta->meta_merge() ); This method returns a reference to a hash describing the meta-data which has to be provided by making use of the builder's C functionality. This includes the C and C data. Any arguments will be appended to the generated array. =head2 provides use YAML; print Dump( [ $meta->provides() ] ); This method attempts to load L. If this succeeds, it returns a C entry suitable for inclusion in L data (i.e. C<'provides'> followed by a hash reference). If it can not load the required module, it returns nothing. =head2 requires use YAML; print Dump( $meta->requires() ); This method computes and returns a reference to a hash describing the modules required to run the C package, suitable for use in a F C key, or a F C key. Any additional arguments will be appended to the generated hash. In addition, unless L is true, configuration-specific modules may be added. =head2 requires_perl print 'This package requires Perl ', $meta->requires_perl(), "\n"; This method returns the version of Perl required by the package. =head1 ATTRIBUTES This class has no public attributes. =head1 ENVIRONMENT =head2 MAKING_MODULE_DISTRIBUTION This environment variable should be set to a true value if you are making a distribution. This ensures that no configuration-specific information makes it into F. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2010-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/inc/My/Module/Mock_Tokenizer.pm000444000765000024 602113237102475 20662 0ustar00tomstaff000000000000package My::Module::Mock_Tokenizer; use 5.006; use strict; use warnings; use Carp; our $VERSION = '0.055'; sub new { my ( $class, %arg ) = @_; return bless \%arg, ref $class || $class; } sub capture { my ( $self ) = @_; 'ARRAY' eq ref $self->{capture} or return; return @{ $self->{capture} }; } sub cookie { my ( $self, $cookie ) = @_; return $self->{cookie}{$cookie}; } sub modifier_modify {} sub __recognize_postderef { my ( $self ) = @_; return $self->{postderef}; } 1; __END__ =head1 NAME My::Module::Mock_Tokenizer - Mock tokenizer for t/*.t =head1 SYNOPSIS use lib qw{ inc }; use My::Module::Mock_Tokenizer; my $tokenizer = My::Module::Mock_Tokenizer->new(); =head1 DESCRIPTION This Perl class is private to the C package, and may be modified or retracted without notice. Documentation is for the benefit of the author. represents a mock tokenizer to be used in testing. It implements those methods that the author finds useful. =head1 METHODS This class supports the following public methods: =head2 new my $tokenizer = My::Module::Mock_Tokenizer->new(); This static method instantiates the tokenizer. In addition to the invocant it takes arbitrary name/value pairs of arguments. These arguments are made into a hash, and a blessed reference to this hash is returned. The arguments are not validated, but may be used in methods as documented below. =head2 capture say "Capture: '$_'" for $tokenizer->capture(); If C<< $tokenizer->{capture} >> is an array reference, the contents of the array are returned. Otherwise nothing is returned. =head2 cookie my $cookie = $tokenizer->cookie( $name ); This method returns C<< $tokenizer->{cookie}{$name} >>. If you want to specify a value for this, recall that cookies are code references. =head2 modifier_modify $tokenizer->modifier_modify( i => 1 ); This method does nothing and returns nothing. =head2 __recognize_postderef $tokenizer->__recognize_postderef() and say 'We recognize postfix dereferences'; This method returns the value of C<< $tokenizer->{postderef} >>. =head1 SEE ALSO L =head1 SUPPORT This module is private to the C package. It is unsupported in the sense that the author reserves the right to modify or retract it without prior appeoval. Bug reports filed via L, or in electronic mail to the author will be accepted if they document a problem with this module that results in spurious test results. =head1 AUTHOR Tom Wyant (wyant at cpan dot org) =head1 COPYRIGHT AND LICENSE Copyright (C) 2015-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/inc/My/Module/Test.pm000444000765000024 4440113237102475 16702 0ustar00tomstaff000000000000package My::Module::Test; use strict; use warnings; use Exporter qw{ import }; use PPIx::Regexp; use PPIx::Regexp::Dumper; use PPIx::Regexp::Element; use PPIx::Regexp::Tokenizer; use PPIx::Regexp::Util qw{ __instance }; use Scalar::Util qw{ looks_like_number refaddr }; use Test::More 0.88; our $VERSION = '0.055'; our @EXPORT_OK = qw{ cache_count choose class cmp_ok content count diag different done_testing dump_result error fail false finis equals navigate note parse pass plan ppi result skip tokenize true value }; our @EXPORT = @EXPORT_OK; ## no critic (ProhibitAutomaticExportation) push @EXPORT_OK, qw{ __quote }; my ( $initial_class, # For static methods; set by parse() or tokenize() $kind, # of thing; set by parse() or tokenize() $nav, # Navigation used to get to current object, as a # string. $obj, # Current object: # PPIx::Regexp::Tokenizer if set by tokenize(), # PPIx::Regexp if set by parse(), or # PPIx::Regexp::Element if set by navigate(). $parse, # Result of parse: # array ref if set by tokenize(), or # PPIx::Regexp object if set by parse() $result, # Operation result. ); sub cache_count { ## no critic (RequireArgUnpacking) my ( $expect ) = @_; defined $expect or $expect = 0; $obj = undef; $parse = undef; _pause(); $result = PPIx::Regexp->__cache_size(); @_ = ( $result, $expect, "Should be $expect leftover cache contents" ); goto &is; } sub choose { my @args = @_; $obj = $parse; return navigate( @args ); } sub class { ## no critic (RequireArgUnpacking) my ( $class ) = @_; $result = ref $obj || $obj; if ( defined $class ) { @_ = ( $obj, $class, "$kind $nav" ); goto &isa_ok; } else { @_ = ( ref $obj || undef, $class, "Class of $kind $nav" ); goto &is; } } sub content { ## no critic (RequireArgUnpacking) unshift @_, 'content'; goto &_method_result; } sub count { ## no critic (RequireArgUnpacking) my ( @args ) = @_; my $expect = pop @args; if ( ref $parse eq 'ARRAY' ) { $result = @{ $parse }; @_ = ( $result, $expect, "Expect $expect tokens" ); } elsif ( ref $obj eq 'ARRAY' ) { $result = @{ $obj }; @_ = ( $result, $expect, "Expect $expect tokens" ); } elsif ( $obj->can( 'children' ) ) { $result = $obj->children(); @_ = ( $result, $expect, "Expect $expect children" ); } else { $result = $obj->can( 'children' ); @_ = ( $result, ref( $obj ) . "->can( 'children')" ); goto &ok; } goto &is; } sub different { ## no critic (RequireArgUnpacking) my @args = @_; @args < 3 and unshift @args, $obj; my ( $left, $right, $name ) = @args; if ( ! defined $left && ! defined $right ) { @_ = ( undef, $name ); } elsif ( ! defined $left || ! defined $right ) { @_ = ( 1, $name ); } elsif ( ref $left && ref $right ) { @_ = ( refaddr( $left ) != refaddr( $right ), $name ); } elsif ( ref $left || ref $right ) { @_ = ( 1, $name ); } elsif ( looks_like_number( $left ) && looks_like_number( $right ) ) { @_ = ( $left != $right, $name ); } else { @_ = ( $left ne $right, $name ); } goto &ok; } sub dump_result { my ( $opt, @args ) = _parse_constructor_args( { test => 1 }, @_ ); if ( $opt->{test} ) { my ( $expect, $name ) = splice @args, -2; my $got = PPIx::Regexp::Dumper->new( $obj, @args )->string(); @_ = ( $got, $expect, $name ); goto &is; } elsif ( __instance( $result, 'PPIx::Regexp::Tokenizer' ) || __instance( $result, 'PPIx::Regexp::Element' ) ) { diag( PPIx::Regexp::Dumper->new( $obj, @args )->string() ); } elsif ( eval { require YAML; 1; } ) { diag( "Result dump:\n", YAML::Dump( $result ) ); } elsif ( eval { require Data::Dumper; 1 } ) { diag( "Result dump:\n", Data::Dumper::Dumper( $result ) ); } else { diag( "Result dump unavailable.\n" ); } return; } sub equals { ## no critic (RequireArgUnpacking) my @args = @_; @args < 3 and unshift @args, $obj; my ( $left, $right, $name ) = @args; if ( ! defined $left && ! defined $right ) { @_ = ( 1, $name ); } elsif ( ! defined $left || ! defined $right ) { @_ = ( undef, $name ); } elsif ( ref $left && ref $right ) { @_ = ( refaddr( $left ) == refaddr( $right ), $name ); } elsif ( ref $left || ref $right ) { @_ = ( undef, $name ); } elsif ( looks_like_number( $left ) && looks_like_number( $right ) ) { @_ = ( $left == $right, $name ); } else { @_ = ( $left eq $right, $name ); } goto &ok; } sub error { ## no critic (RequireArgUnpacking) unshift @_, 'error'; goto &_method_result; } sub false { ## no critic (RequireArgUnpacking) my ( $method, $args ) = @_; ref $args eq 'ARRAY' or $args = [ $args ]; my $class = ref $obj; if ( $obj->can( $method ) ) { $result = $obj->$method( @{ $args } ); my $fmtd = _format_args( $args ); @_ = ( ! $result, "$class->$method$fmtd is false" ); } else { $result = undef; @_ = ( undef, "$class->$method() exists" ); } goto &ok; } sub finis { ## no critic (RequireArgUnpacking) $obj = $parse = $result = undef; _pause(); $result = PPIx::Regexp::Element->__parent_keys(); @_ = ( $result, 0, 'Should be no leftover objects' ); goto &is; } { my %array = map { $_ => 1} qw{ children delimiters finish schildren start tokens type }; sub navigate { my @args = @_; my $scalar = 1; @args > 1 and ref $args[-1] eq 'ARRAY' and @{ $args[-1] } == 0 and $array{$args[-2]} and $scalar = 0; my @nav = (); while ( @args ) { if ( __instance( $args[0], 'PPIx::Regexp::Element' ) ) { $obj = shift @args; } elsif ( ref $obj eq 'ARRAY' ) { my $inx = shift @args; push @nav, $inx; $obj = $obj->[$inx]; } else { my $method = shift @args; my $args = shift @args; ref $args eq 'ARRAY' or $args = [ $args ]; push @nav, $method, $args; $obj->can( $method ) or return; if ( @args || $scalar ) { $obj = $obj->$method( @{ $args } ) or return; } else { $obj = [ $obj->$method( @{ $args } ) ]; } } } $nav = __quote( @nav ); $nav =~ s/ ' ( \w+ ) ' , /$1 =>/smxg; $nav =~ s/ \[ \s+ \] /[]/smxg; $result = $obj; return $obj; } } sub parse { ## no critic (RequireArgUnpacking) my ( $opt, $regexp, @args ) = _parse_constructor_args( { test => 1 }, @_ ); $initial_class = 'PPIx::Regexp'; $kind = 'element'; $result = $obj = $parse = PPIx::Regexp->new( $regexp, @args ); $nav = ''; $opt->{test} or return; @_ = ( $parse, 'PPIx::Regexp', $regexp ); goto &isa_ok; } sub ppi { ## no critic (RequireArgUnpacking) my @args = @_; my $expect = pop @args; $result = undef; defined $obj and $result = $obj->ppi()->content(); my $safe; if ( defined $result ) { ($safe = $result) =~ s/([\\'])/\\$1/smxg; } else { $safe = 'undef'; } @_ = ( $result, $expect, "$kind $nav ppi() content '$safe'" ); goto &is; } sub result { return $result; } sub tokenize { ## no critic (RequireArgUnpacking) my ( $opt, $regexp, @args ) = _parse_constructor_args( { test => 1, tokens => 1 }, @_ ); my %args = @args; $initial_class = ( defined $args{parse} && $args{parse} eq 'string') ? 'PPIx::Regexp::StringTokenizer' : 'PPIx::Regexp::Tokenizer'; $kind = 'token'; $obj = $initial_class->new( $regexp, @args ); if ( $obj && $opt->{tokens} ) { $parse = [ $obj->tokens() ]; } else { $parse = []; } $result = $parse; $nav = ''; $opt->{test} or return; @_ = ( $obj, 'PPIx::Regexp::Tokenizer', $regexp ); goto &isa_ok; } sub true { ## no critic (RequireArgUnpacking) my ( $method, $args ) = @_; ref $args eq 'ARRAY' or $args = [ $args ]; my $class = ref $obj; if ( $obj->can( $method ) ) { $result = $obj->$method( @{ $args } ); my $fmtd = _format_args( $args ); @_ = ( $result, "$class->$method$fmtd is true" ); } else { $result = undef; @_ = ( undef, "$class->$method() exists" ); } goto &ok; } sub value { ## no critic (RequireArgUnpacking) my ( $method, $args, $expect ) = @_; ref $args eq 'ARRAY' or $args = [ $args ]; my $invocant = $obj || $initial_class; my $class = ref $obj || $obj || $initial_class; if ( ! $invocant->can( $method ) ) { @_ = ( undef, "$class->$method() exists" ); goto &ok; } $result = ref $expect eq 'ARRAY' ? [ $invocant->$method( @{ $args } ) ] : $invocant->$method( @{ $args } ); my $fmtd = _format_args( $args ); my $answer = _format_args( [ $expect ], bare => 1 ); @_ = ( $result, $expect, "${class}->$method$fmtd is $answer" ); if ( ref $result ) { goto &is_deeply; } else { goto &is; } } sub _format_args { my ( $args, %opt ) = @_; my @rslt; foreach my $arg ( @{ $args } ) { if ( ! defined $arg ) { push @rslt, 'undef'; } elsif ( looks_like_number( $arg ) ) { push @rslt, $arg; } else { push @rslt, $arg; $rslt[-1] =~ s/ ' /\\'/smxg; $rslt[-1] = "'$rslt[-1]'"; } } my $string = join ', ', @rslt; $opt{bare} and return $string; @rslt or return '()'; return "( $string )"; } sub _method_result { ## no critic (RequireArgUnpacking) my ( $method, @args ) = @_; my $expect = pop @args; $result = undef; defined $obj and $result = $obj->$method(); my $safe; if ( defined $result ) { ($safe = $result) =~ s/([\\'])/\\$1/smxg; $safe = "'$safe'"; } else { $safe = 'undef'; } @_ = ( $result, $expect, "$kind $nav $method $safe" ); goto &is; } sub _parse_constructor_args { my ( $opt, @args ) = @_; my @rslt = ( $opt ); foreach my $arg ( @args ) { if ( $arg =~ m/ \A - -? (no)? (\w+) \z /smx && exists $opt->{$2} ) { $opt->{$2} = !$1; } else { push @rslt, $arg; } } return @rslt; } sub _pause { if ( eval { require Time::HiRes; 1 } ) { # Cargo cult programming. Time::HiRes::sleep( 0.1 ); # Something like this is } else { # in PPI's sleep 1; # t/08_regression.t, and } # who am I to argue? return; } # quote a string. sub __quote { my @args = @_; my @rslt; foreach my $item ( @args ) { if ( __instance( $item, 'PPIx::Regexp::Element' ) ) { $item = $item->content(); } if ( ! defined $item ) { push @rslt, 'undef'; } elsif ( ref $item eq 'ARRAY' ) { push @rslt, join( ' ', '[', __quote( @{ $item } ), ']' ); } elsif ( looks_like_number( $item ) ) { push @rslt, $item; } else { $item =~ s/ ( [\\'] ) /\\$1/smxg; push @rslt, "'$item'"; } } return join( ', ', @rslt ); } 1; __END__ =head1 NAME My::Module::Test - support for testing PPIx::Regexp =head1 SYNOPSIS use lib qw{ inc }; use My::Module::Test; parse ( '/foo/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); # and so on =head1 DETAILS This package exports various subroutines in support of testing C. Most of these are tests, with C doing the dirty work. A few simply set up data for tests. The whole test rig works by parsing (or tokenizing) a regular expression, followed by a series of unit tests on the results of the parse. Each set of unit tests is performed by selecting an object to test using the C or C subroutine, followed by the tests to be performed on that object. A few tests do not test parse objects, but rather the state of the system as a whole. The following subroutines are exported: =head2 cache_count cache_count( 1 ); This test compares the number of objects in the C cache to its argument, succeeding if they are equal. If no argument is passed, the default is 0. =head2 choose choose( 2 ); # For tokenizer choose( child => 1, child => 2, type => 0 ); # For full parse This subroutine does not itself represent a test. It chooses an object from the parse tree for further testing. If testing a tokenizer, the argument is the token number (from 0) to select. If testing a full parse, the arguments are the navigation methods used to reach the object to be tested, starting from the C object. The arguments to the methods are passed in an array reference, but if there is a single argument it can be passed as a scalar, as in the example. =head2 class class( 'PPIx::Regexp::Token::Structure' ); This test checks to see if the current object is of the given class, and succeeds if it is. If the current object is C, the test fails. =head2 content content( '\N{LATIN SMALL LETTER A}' ); This test checks to see if the C method of the current object is equal to the given string. If the current object is C, the test fails. =head2 cmp_ok This subroutine is exported from L. =head2 count count( 42 ); This test checks the number of objects returned by an operation that returns more than one object. It succeeds if the number of objects returned is equal to the given number. This test is valid only after C, or a C or C whose argument list ends in one of children => [] finish => [] start => [] type => [] =head2 different different( $o1, $o2, 'Test name' ); This test compares two things, succeeding if they are different. References are compared by reference address and scalars by value (numeric or string comparison as appropriate). If the first argument is omitted it defaults to the current object. =head2 dump_result dump_result( tokens => 1, <<'EOD', 'Test tokenization dump' ); ... expected dump here ... EOD This test performs the specified dump on the current object and succeeds if the result matches the expectation. The name of the test is the last argument, and the expected result is the next-to-last argument. All other arguments are passed to L. Well, almost all other arguments are passed to the dumper. You can specify C<--notest> to skip the test. In this case the result of the last operation is dumped. L is used if appropriate; otherwise you get a L dump if that is available, or a L dump if not. If no dumper class can be found, a diagnostic is produced. You can also specify C<--test>, but this is the default. This option is removed from the argument list before the test name (etc) is determined. =head2 equals equals( $o1, $o2, 'Test name' ); This test compares two things, succeeding if they are equal. References are compared by reference address and scalars by value (numeric or string comparison as appropriate). If the first argument is omitted it defaults to the current object. =head2 false false( significant => [] ); This test succeeds if the given method, with the given arguments, called on the current object, returns a false value. =head2 finis finis(); This test should be last in a series, and no references to parse objects should be held when it is run. It checks the number of objects in the internal C<%parent> hash, and succeeds if it is zero. =head2 navigate navigate( snext_sibling => [] ); Like C, this is not a test, but selects an object for testing. Unlike C, selection starts from the current object, not the top of the parse tree. =head2 parse parse( 's/foo/bar/g' ); This test parses the given regular expression into a C object, and succeeds if a C object was in fact generated. If you specify argument C<--notest>, the parse is done but no test is performed. You would do this if you expected the parse to fail (e.g. you are testing error handling). You can also explicitly specify C<--test>, but this is the default. All other arguments are passed to the L constructor. =head2 plan This subroutine is exported from L. =head2 content ppi( '$foo' ); This test calls the current object's C method, and checks to see if the content of the returned L is equal to the given string. If the current object is C or does not have a C method, the test fails. =head2 result my $val = result(); This subroutine returns the result of the most recent operation that actually produces one. It should be called immediately after the operation, mostly because I have not documented all the subroutines that produce a result. =head2 tokenize tokenize( 'm/foo/smx' ); This test tokenizes the given regular expression into a C object, and succeeds if a C object was in fact generated. If you specify argument C<--notest>, the parse is done but no test is performed. You would do this if you expected the parse to fail (e.g. you are testing error handling). You can also explicitly specify C<--test>, but this is the default. If you specify argument C<--notokens>, the tokenizer is built, but the tokens are not extracted. You would do this when you want a subsequent operation to call C. You can also explicitly specify C<--tokens>, but this is the default. All other arguments are passed to the L constructor. =head2 true true( significant => [] ); This test succeeds if the given method, with the given arguments, called on the current object, returns a true value. =head2 value value( max_capture_number => [], 3 ); This test succeeds if the given method, with the given arguments, called on the current object, returns the given value. If the current object is undefined, the given method is called on the intended initial class, otherwise there would be no way to test the errstr() method. The result of the method call is accessable via the L subroutine. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib000755000765000024 013237102475 13430 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx000755000765000024 013237102475 14250 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp.pm000444000765000024 7022113237102475 16217 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp - Represent a regular expression of some sort =head1 SYNOPSIS use PPIx::Regexp; use PPIx::Regexp::Dumper; my $re = PPIx::Regexp->new( 'qr{foo}smx' ); PPIx::Regexp::Dumper->new( $re ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION The purpose of the F package is to parse regular expressions in a manner similar to the way the L package parses Perl. This class forms the root of the parse tree, playing a role similar to L. This package shares with L the property of being round-trip safe. That is, my $expr = 's/ ( \d+ ) ( \D+ ) /$2$1/smxg'; my $re = PPIx::Regexp->new( $expr ); print $re->content() eq $expr ? "yes\n" : "no\n" should print 'yes' for any valid regular expression. Navigation is similar to that provided by L. That is to say, things like C, C, C and so on all work pretty much the same way as in L. The class hierarchy is also similar to L. Except for some utility classes (the dumper, the lexer, and the tokenizer) all classes are descended from L, which provides basic navigation. Tokens are descended from L, which provides content. All containers are descended from L, which provides for children, and all structure elements are descended from L, which provides beginning and ending delimiters, and a type. There are two features of L that this package does not provide - mutability and operator overloading. There are no plans for serious mutability, though something like L's C functionality might be considered. Similarly there are no plans for operator overloading, which appears to the author to represent a performance hit for little tangible gain. =head1 NOTICE The use of this class to parse non-regexp quote-like strings was an experiment that I consider failed. Therefore this use is B in favor of L. Six months after the release of version 0.053, the first use of the C argument to L will result in a warning. Six months after that, all uses of the C argument will result in a warning. After another six months, the C argument will become fatal. The author will attempt to preserve the documented interface, but if the interface needs to change to correct some egregiously bad design or implementation decision, then it will change. Any incompatible changes will go through a deprecation cycle. The goal of this package is to parse well-formed regular expressions correctly. A secondary goal is not to blow up on ill-formed regular expressions. The correct identification and characterization of ill-formed regular expressions is B a goal of this package, nor is the consistent parsing of ill-formed regular expressions from release to release. This policy attempts to track features in development releases as well as public releases. However, features added in a development release and then removed before the next production release B be tracked, and any functionality relating to such features B. The issue here is the potential re-use (with different semantics) of syntax that did not make it into the production release. From time to time the Perl regular expression engine changes in ways that change the parse of a given regular expression. When these changes occur, C will be changed to produce the more modern parse. Known examples of this include: =over =item C<$(> no longer interpolates as of Perl 5.005, per C. Newer Perls seem to parse this as C (i.e. and end-of-string or newline assertion) followed by an open parenthesis, and that is what C does. =item C<$)> and C<$|> also seem to parse as the C<$> assertion followed by the relevant meta-character, though I have no documentation reference for this. =item C<@+> and C<@-> no longer interpolate as of Perl 5.9.4 per C. Subsequent Perls treat C<@+> as a quantified literal and C<@-> as two literals, and that is what C does. Note that subscripted references to these arrays B interpolate, and are so parsed by C. =item Only space and horizontal tab are whitespace as of Perl 5.23.4 when inside a bracketed character class inside an extended bracketed character class, per C. Formerly any white space character parsed as whitespace. This change in C will be reverted if the change in Perl does not make it into Perl 5.24.0. =item Unescaped literal left curly brackets These are being removed in positions where quantifiers are legal, so that they can be used for new functionality. Some of them are gone in 5.25.1, others will be removed in a future version of Perl. In situations where they have been removed, L will return the version in which they were removed. When the new functionality appears, the parse produced by this software will reflect the new functionality. B that a literal left curly after a literal character was made an error in Perl 5.25.1, but became a warning again in 5.27.1 due to its use in GNU Autoconf. Whether it will ever become illegal again is not clear to me based on the contents of F. At the moment C considers this usage to have been removed in 5.25.1, and this will not change based on anything in 5.27.x. But if 5.26.1 comes out allowing this usage, the removal version will become C. The same will apply to any other usages that were re-allowed in 5.27.1, if I can identify them. =back There are very probably other examples of this. When they come to light they will be documented as producing the modern parse, and the code modified to produce this parse if necessary. The functionality that parses string literals (the C argument to C) was introduced in version 0.045, but its use is discouraged. The preferred package for string literals is L, and once I consider that package to be stable the string literal functionality in this package will be put through a deprecation cycle and removed. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp; use strict; use warnings; use base qw{ PPIx::Regexp::Node }; use PPIx::Regexp::Lexer (); use PPIx::Regexp::StringTokenizer; use PPIx::Regexp::Token::Modifier (); # For its modifier manipulations. use PPIx::Regexp::Tokenizer; use PPIx::Regexp::Util qw{ __choose_tokenizer_class __instance }; use Scalar::Util qw{ refaddr }; our $VERSION = '0.055'; =head2 new my $re = PPIx::Regexp->new('/foo/'); This method instantiates a C object from a string, a L, a L, or a L. Honestly, any L will work, but only the three Regexp classes mentioned previously are likely to do anything useful. Whatever form the argument takes, it is assumed to consist entirely of a valid match, substitution, or C<< qr<> >> string. Optionally you can pass one or more name/value pairs after the regular expression. The possible options are: =over =item default_modifiers array_reference This option specifies a reference to an array of default modifiers to apply to the regular expression being parsed. Each modifier is specified as a string. Any actual modifiers found supersede the defaults. When applying the defaults, C<'?'> and C<'/'> are completely ignored, and C<'^'> is ignored unless it occurs at the beginning of the modifier. The first dash (C<'-'>) causes subsequent modifiers to be negated. So, for example, if you wish to produce a C object representing the regular expression in use re '/smx'; { no re '/x'; m/ foo /; } you would (after some help from L in finding the relevant statements), do something like my $re = PPIx::Regexp->new( 'm/ foo /', default_modifiers => [ '/smx', '-/x' ] ); =item encoding name This option specifies the encoding of the regular expression. This is passed to the tokenizer, which will C the regular expression string before it tokenizes it. For example: my $re = PPIx::Regexp->new( '/foo/', encoding => 'iso-8859-1', ); =item parse parse_type This option specifies what kind of parse is to be done. Possible values are C<'regex'>, C<'string'>, or C<'guess'>. Any value but C<'regex'> is experimental. As it turns out, I consider parsing non-regexp quote-like things with this class to be a failed experiment, and the relevant functionality is being deprecated and removed in favor of L. See above for details. If C<'regex'> is specified, the first argument is expected to be a valid regex, and parsed as though it were. If C<'string'> is specified, the first argument is expected to be a valid string literal and parsed as such. The return is still a C object, but the L and L methods return nothing, and the L method returns the content of the string. If C<'guess'> is specified, this method will try to guess what the first argument is. If the first argument is a L, the guess will reflect the PPI parse. But the guess can be wrong if the first argument is a string representing an unusually-delimited regex. For example, C<'guess'> will parse C<"foo"> as a string, but Perl will parse it as a regex if preceded by a regex binding operator (e.g. C<$x =~ "foo">), as shown by perl -MO=Deparse -e '$x =~ "foo"' which prints $x =~ /foo/u under Perl 5.22.0. The default is C<'regex'>. =item postderef boolean This option is passed on to the tokenizer, where it specifies whether postfix dereferences are recognized in interpolations and code. This experimental feature was introduced in Perl 5.19.5. The default is the value of C<$PPIx::Regexp::Tokenizer::DEFAULT_POSTDEREF>, which is true. When originally introduced this was false, but was documented as becoming true when and if postfix dereferencing became mainstream. The intent to mainstream was announced with Perl 5.23.1, and became official (so to speak) with Perl 5.24.0, so the default became true with L 0.049_01. Note that if L starts unconditionally recognizing postfix dereferences, this argument will immediately become ignored, and will be put through a deprecation cycle and removed. =item strict boolean This option is passed on to the tokenizer and lexer, where it specifies whether the parse should assume C is in effect. The C<'strict'> pragma was introduced in Perl 5.22, and its documentation says that it is experimental, and that there is no commitment to backward compatibility. The same applies to the parse produced when this option is asserted. Also, the usual caveat applies: if C ends up being retracted, this option and all related functionality will be also. Given the nature of C, you should expect that if you assert this option, regular expressions that previously parsed without error might no longer do so. If an element ends up being declared an error because this option is set, its C will be the Perl version at which C started rejecting these elements. The default is false. =item trace number If greater than zero, this option causes trace output from the parse. The author reserves the right to change or eliminate this without notice. =back Passing optional input other than the above is not an error, but neither is it supported. =cut { my $errstr; sub new { my ( $class, $content, %args ) = @_; ref $class and $class = ref $class; $errstr = undef; my $tokenizer_class = __choose_tokenizer_class( $content, \%args ) or do { $errstr = ref $content ? sprintf '%s not supported', ref $content : "Unknown parse type '$args{parse}'"; return; }; my $tokenizer = $tokenizer_class->new( $content, %args ) or do { $errstr = PPIx::Regexp::Tokenizer->errstr(); return; }; my $lexer = PPIx::Regexp::Lexer->new( $tokenizer, %args ); my @nodes = $lexer->lex(); my $self = $class->SUPER::__new( @nodes ); $self->{source} = $content; $self->{failures} = $lexer->failures(); $self->{effective_modifiers} = $tokenizer->__effective_modifiers(); return $self; } sub errstr { return $errstr; } } =head2 new_from_cache This static method wraps L in a caching mechanism. Only one object will be generated for a given L, no matter how many times this method is called. Calls after the first for a given L simply return the same C object. When the C object is returned from cache, the values of the optional arguments are ignored. Calls to this method with the regular expression in a string rather than a L will not be cached. B This method is provided for code like L which might instantiate the same object multiple times. The cache will persist until L is called. =head2 flush_cache $re->flush_cache(); # Remove $re from cache PPIx::Regexp->flush_cache(); # Empty the cache This method flushes the cache used by L. If called as a static method with no arguments, the entire cache is emptied. Otherwise any objects specified are removed from the cache. =cut { my %cache; our $DISABLE_CACHE; # Leave this undocumented, at least for # now. sub __cache_size { return scalar keys %cache; } sub new_from_cache { my ( $class, $content, %args ) = @_; __instance( $content, 'PPI::Element' ) or return $class->new( $content, %args ); $DISABLE_CACHE and return $class->new( $content, %args ); my $addr = refaddr( $content ); exists $cache{$addr} and return $cache{$addr}; my $self = $class->new( $content, %args ) or return; $cache{$addr} = $self; return $self; } sub flush_cache { my @args = @_; ref $args[0] or shift @args; if ( @args ) { foreach my $obj ( @args ) { if ( __instance( $obj, __PACKAGE__ ) && __instance( ( my $parent = $obj->source() ), 'PPI::Element' ) ) { delete $cache{ refaddr( $parent ) }; } } } else { %cache = (); } return; } } sub can_be_quantified { return; } =head2 capture_names foreach my $name ( $re->capture_names() ) { print "Capture name '$name'\n"; } This convenience method returns the capture names found in the regular expression. This method is equivalent to $self->regular_expression()->capture_names(); except that if C<< $self->regular_expression() >> returns C (meaning that something went terribly wrong with the parse) this method will simply return. =cut sub capture_names { my ( $self ) = @_; my $re = $self->regular_expression() or return; return $re->capture_names(); } =head2 delimiters print join("\t", PPIx::Regexp->new('s/foo/bar/')->delimiters()); # prints '// //' When called in list context, this method returns either one or two strings, depending on whether the parsed expression has a replacement string. In the case of non-bracketed substitutions, the start delimiter of the replacement string is considered to be the same as its finish delimiter, as illustrated by the above example. When called in scalar context, you get the delimiters of the regular expression; that is, element 0 of the array that is returned in list context. Optionally, you can pass an index value and the corresponding delimiters will be returned; index 0 represents the regular expression's delimiters, and index 1 represents the replacement string's delimiters, which may be undef. For example, print PPIx::Regexp->new('s{foo}')->delimiters(1); # prints '<>' If the object was not initialized with a valid regexp of some sort, the results of this method are undefined. =cut sub delimiters { my ( $self, $inx ) = @_; my @rslt; foreach my $method ( qw{ regular_expression replacement } ) { defined ( my $obj = $self->$method() ) or next; push @rslt, $obj->delimiters(); } defined $inx and return $rslt[$inx]; wantarray and return @rslt; defined wantarray and return $rslt[0]; return; } =head2 errstr This static method returns the error string from the most recent attempt to instantiate a C. It will be C if the most recent attempt succeeded. =cut # defined above, just after sub new. sub explain { return; } =head2 failures print "There were ", $re->failures(), " parse failures\n"; This method returns the number of parse failures. This is a count of the number of unknown tokens plus the number of unterminated structures plus the number of unmatched right brackets of any sort. =cut sub failures { my ( $self ) = @_; return $self->{failures}; } =head2 max_capture_number print "Highest used capture number ", $re->max_capture_number(), "\n"; This convenience method returns the highest capture number used by the regular expression. If there are no captures, the return will be 0. This method is equivalent to $self->regular_expression()->max_capture_number(); except that if C<< $self->regular_expression() >> returns C (meaning that something went terribly wrong with the parse) this method will too. =cut sub max_capture_number { my ( $self ) = @_; my $re = $self->regular_expression() or return; return $re->max_capture_number(); } =head2 modifier my $re = PPIx::Regexp->new( 's/(foo)/${1}bar/smx' ); print $re->modifier()->content(), "\n"; # prints 'smx'. This method retrieves the modifier of the object. This comes from the end of the initializing string or object and will be a L. B that this object represents the actual modifiers present on the regexp, and does not take into account any that may have been applied by default (i.e. via the C argument to C). For something that takes account of default modifiers, see L, below. In the event of a parse failure, there may not be a modifier present, in which case nothing is returned. =cut sub modifier { my ( $self ) = @_; return $self->_component( 'PPIx::Regexp::Token::Modifier' ); } =head2 modifier_asserted my $re = PPIx::Regexp->new( '/ . /', default_modifiers => [ 'smx' ] ); print $re->modifier_asserted( 'x' ) ? "yes\n" : "no\n"; # prints 'yes'. This method returns true if the given modifier is asserted for the regexp, whether explicitly or by the modifiers passed in the C argument. Starting with version 0.036_01, if the argument is a single-character modifier followed by an asterisk (intended as a wild card character), the return is the number of times that modifier appears. In this case an exception will be thrown if you specify a multi-character modifier (e.g. C<'ee*'>), or if you specify one of the match semantics modifiers (e.g. C<'a*'>). =cut sub modifier_asserted { my ( $self, $modifier ) = @_; return PPIx::Regexp::Token::Modifier::__asserts( $self->{effective_modifiers}, $modifier, ); } # This is a kluge for both determining whether the object asserts # modifiers (hence the 'ductype') and determining whether the given # modifier is actually asserted. The signature is the invocant and the # modifier name, which must not be undef. The return is a boolean. *__ducktype_modifier_asserted = \&modifier_asserted; # As of Perl 5.21.1 you can not leave off the type of a '?'-delimited # regexp. Because this is not associated with any single child we # compute it here. sub perl_version_removed { my ( $self ) = @_; my $v = $self->SUPER::perl_version_removed(); defined $v and $v <= 5.021001 and return $v; defined( my $delim = $self->delimiters() ) or return $v; '??' eq $delim and '' eq $self->type()->content() and return '5.021001'; return $v; } =head2 regular_expression my $re = PPIx::Regexp->new( 's/(foo)/${1}bar/smx' ); print $re->regular_expression()->content(), "\n"; # prints '/(foo)/'. This method returns that portion of the object which actually represents a regular expression. =cut sub regular_expression { my ( $self ) = @_; return $self->_component( 'PPIx::Regexp::Structure::Regexp' ); } =head2 replacement my $re = PPIx::Regexp->new( 's/(foo)/${1}bar/smx' ); print $re->replacement()->content(), "\n"; # prints '${1}bar/'. This method returns that portion of the object which represents the replacement string. This will be C unless the regular expression actually has a replacement string. Delimiters will be included, but there will be no beginning delimiter unless the regular expression was bracketed. =cut sub replacement { my ( $self ) = @_; return $self->_component( 'PPIx::Regexp::Structure::Replacement' ); } =head2 source my $source = $re->source(); This method returns the object or string that was used to instantiate the object. =cut sub source { my ( $self ) = @_; return $self->{source}; } =head2 type my $re = PPIx::Regexp->new( 's/(foo)/${1}bar/smx' ); print $re->type()->content(), "\n"; # prints 's'. This method retrieves the type of the object. This comes from the beginning of the initializing string or object, and will be a L whose C is one of 's', 'm', 'qr', or ''. =cut sub type { my ( $self ) = @_; return $self->_component( 'PPIx::Regexp::Token::Structure' ); } sub _component { my ( $self, $class ) = @_; foreach my $elem ( $self->children() ) { $elem->isa( $class ) and return $elem; } return; } 1; __END__ =head1 RESTRICTIONS By the nature of this module, it is never going to get everything right. Many of the known problem areas involve interpolations one way or another. =head2 Ambiguous Syntax Perl's regular expressions contain cases where the syntax is ambiguous. A particularly egregious example is an interpolation followed by square or curly brackets, for example C<$foo[...]>. There is nothing in the syntax to say whether the programmer wanted to interpolate an element of array C<@foo>, or whether he wanted to interpolate scalar C<$foo>, and then follow that interpolation by a character class. The F documentation notes that in this case what Perl does is to guess. That is, it employs various heuristics on the code to try to figure out what the programmer wanted. These heuristics are documented as being undocumented (!) and subject to change without notice. Given this situation, this module's chances of duplicating every Perl version's interpretation of every regular expression are pretty much nil. What it does now is to assume that square brackets containing B an integer or an interpolation represent a subscript; otherwise they represent a character class. Similarly, curly brackets containing B a bareword or an interpolation are a subscript; otherwise they represent a quantifier. =head2 Changes in Syntax Sometimes the introduction of new syntax changes the way a regular expression is parsed. For example, the C<\v> character class was introduced in Perl 5.9.5. But it did not represent a syntax error prior to that version of Perl, it was simply parsed as C. So $ perl -le 'print "v" =~ m/\v/ ? "yes" : "no"' prints "yes" under Perl 5.8.9, but "no" under 5.10.0. C generally assumes the more modern parse in cases like this. =head2 Equivocation Very occasionally, a construction will be removed and then added back -- and then, conceivably, removed again. In this case, the plan is for L to return the earliest version in which the construction appeared, and L to return the version after the last version in which it appeared (whether production or development), or C if it is in the highest-numbered Perl. The constructions involved in this are: =head3 Un-escaped literal left curly after literal That is, something like C<< qr >>. This was made an error in C<5.25.1>, and it was an error in C<5.26.0>. But it became a warning again in C<5.27.1>. The F says it was re-instated because the changes broke GNU Autoconf, and the warning message says it will be removed in Perl C<5.30>. Accordingly, L returns C<5.0>. At the moment L returns C<'5.025001'>, but if this construction warns in Perl C<5.26.1> this will become C. This is not quite the same as described above, but is consistent with the L near the beginning of this document. =head2 Static Parsing It is well known that Perl can not be statically parsed. That is, you can not completely parse a piece of Perl code without executing that same code. Nevertheless, this class is trying to statically parse regular expressions. The main problem with this is that there is no way to know what is being interpolated into the regular expression by an interpolated variable. This is a problem because the interpolated value can change the interpretation of adjacent elements. This module deals with this by making assumptions about what is in an interpolated variable. These assumptions will not be enumerated here, but in general the principal is to assume the interpolated value does not change the interpretation of the regular expression. For example, my $foo = 'a-z]'; my $re = qr{[$foo}; is fine with the Perl interpreter, but will confuse the dickens out of this module. Similarly and more usefully, something like my $mods = 'i'; my $re = qr{(?$mods:foo)}; or maybe my $mods = 'i'; my $re = qr{(?$mods)$foo}; probably sets a modifier of some sort, and that is how this module interprets it. If the interpolation is B about modifiers, this module will get it wrong. Another such semi-benign example is my $foo = $] >= 5.010 ? '?' : ''; my $re = qr{($foo\w+)}; which will parse, but this module will never realize that it might be looking at a named capture. =head2 Non-Standard Syntax There are modules out there that alter the syntax of Perl. If the syntax of a regular expression is altered, this module has no way to understand that it has been altered, much less to adapt to the alteration. The following modules are known to cause problems: L, which renders Perl as XML. L, which causes Perl to interpret suffixed empty brackets as dereferencing the thing they suffix. L, which recognizes ANSI C trigraphs, allowing Perl to be written in the ISO 646 character set. L. Enough said. L, which back-ports some of the Perl 6 regular expression syntax to Perl 5. L, which extends regular expressions in various ways, some of which seem to conflict with Perl 5.010. =head1 SEE ALSO L, which parses a bare regular expression (without enclosing C, C, or whatever) and uses a different navigation model. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp000755000765000024 013237102475 15502 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp/Constant.pm000444000765000024 1376713237102475 20024 0ustar00tomstaff000000000000package PPIx::Regexp::Constant; use strict; use warnings; our $VERSION = '0.055'; use base qw{ Exporter }; our @EXPORT_OK = qw{ COOKIE_CLASS COOKIE_QUANT COOKIE_QUOTE COOKIE_REGEX_SET FALSE LITERAL_LEFT_CURLY_ALLOWED LITERAL_LEFT_CURLY_REMOVED_PHASE_1 LITERAL_LEFT_CURLY_REMOVED_PHASE_2 MINIMUM_PERL MODIFIER_GROUP_MATCH_SEMANTICS MSG_PROHIBITED_BY_STRICT NODE_UNKNOWN RE_CAPTURE_NAME STRUCTURE_UNKNOWN TOKEN_LITERAL TOKEN_UNKNOWN TRUE }; use constant COOKIE_CLASS => ']'; use constant COOKIE_QUANT => '}'; use constant COOKIE_QUOTE => '\\E'; use constant COOKIE_REGEX_SET => '])'; use constant FALSE => 0; use constant TRUE => 1; use constant LITERAL_LEFT_CURLY_ALLOWED => undef; use constant LITERAL_LEFT_CURLY_REMOVED_PHASE_1 => '5.025001'; use constant LITERAL_LEFT_CURLY_REMOVED_PHASE_2 => undef; use constant MINIMUM_PERL => '5.000'; use constant MODIFIER_GROUP_MATCH_SEMANTICS => 'match_semantics'; use constant MSG_PROHIBITED_BY_STRICT => q; use constant NODE_UNKNOWN => 'PPIx::Regexp::Node::Unknown'; # The perlre for Perl 5.010 says: # # Currently NAME is restricted to simple identifiers only. In # other words, it must match "/^[_A-Za-z][_A-Za-z0-9]*\z/" or # its Unicode extension (see utf8), though it isn't extended by # the locale (see perllocale). use constant RE_CAPTURE_NAME => ' [_[:alpha:]] \w* '; use constant STRUCTURE_UNKNOWN => 'PPIx::Regexp::Structure::Unknown'; use constant TOKEN_LITERAL => 'PPIx::Regexp::Token::Literal'; use constant TOKEN_UNKNOWN => 'PPIx::Regexp::Token::Unknown'; 1; __END__ =head1 NAME PPIx::Regexp::Constant - Constants for the PPIx::Regexp system =head1 SYNOPSIS use PPIx::Regexp::Constant qw{ TOKEN_UNKNOWN } print "An unknown token's class is TOKEN_UNKNOWN\n"; =head1 INHERITANCE C is an L. C has no descendants. =head1 DETAILS This module defines manifest constants for use by the various C modules. These constants are to be considered B to the C system, and the author reserves the right to change them without notice. This module exports the following manifest constants: =head2 COOKIE_CLASS The name of the cookie used to control the construction of character classes. This cookie is set in L when the left square bracket is encountered, and cleared in the same module when a right square bracket is encountered. =head2 COOKIE_QUANT The name of the cookie used to control the construction of curly bracketed quantifiers. This cookie is set in L when a left curly bracket is encountered. It requests itself to be cleared on encountering anything other than a literal comma, a literal digit, or an interpolation, or if more than one comma is encountered. If it survives until L processes the right curly bracket, it is cleared there. =head2 COOKIE_QUOTE The name of the cookie used to control the parsing of C<\Q ... \E> quoted literals. This cookie is set in L when a C<\Q> is encountered, and it persists until the next C<\E>. =head2 COOKIE_REGEX_SET The name of the cookie used to control regular expression sets. =head2 LITERAL_LEFT_CURLY_ALLOWED The Perl version at which allowed unescaped literal left curly brackets were removed. This may make more sense if I mention that its value is C. =head2 LITERAL_LEFT_CURLY_REMOVED_PHASE_1 The Perl version at which the first phase of unescaped literal left curly bracket removal took place. The value of this constant is C<'5.025001'>. =head2 LITERAL_LEFT_CURLY_REMOVED_PHASE_2 The Perl version at which the second phase of unescaped literal left curly bracket removal took place. The value of this constant is C, but it will be assigned a value when the timing of the second phase is known. =head2 MINIMUM_PERL The minimum version of Perl understood by this parser, as a float. It is currently set to 5.000, since that is the minimum version of Perl accessible to the author. =head2 MODIFIER_GROUP_MATCH_SEMANTICS The name of the L group used to control match semantics. =head2 MSG_PROHIBITED_BY_STRICT An appropriate error message for an unknown entity created because C<'strict'> was in effect. This is rank ad-hocery, and more than usually subject to being changed, without any notice whatsoever. Caveat user. =head2 NODE_UNKNOWN The name of the class that represents an unknown node. That is, L. =head2 RE_CAPTURE_NAME A string representation of a regular expression that matches the name of a named capture buffer. =head2 STRUCTURE_UNKNOWN The name of the class that represents an unknown structure. That is, L. =head2 TOKEN_LITERAL The name of the class that represents a literal token. That is, L. =head2 TOKEN_UNKNOWN The name of the class that represents the unknown token. That is, L. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Dumper.pm000444000765000024 4632413237102475 17462 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Dumper - Dump the results of parsing regular expressions =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class generates a formatted dump of a L object (or any subclass thereof), a L object, or a string that can be made into one of these. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Dumper; use strict; use warnings; use base qw{ PPIx::Regexp::Support }; use Carp; use Scalar::Util qw{ blessed looks_like_number }; use PPIx::Regexp; use PPIx::Regexp::Tokenizer; use PPIx::Regexp::Util qw{ __choose_tokenizer_class __instance }; our $VERSION = '0.055'; =head2 new my $dumper = PPIx::Regexp::Dumper->new( '/foo/', ordinal => 1, ); This static method instantiates the dumper. It takes the string, L, L, or L to be dumped as the first argument. Optional further arguments may be passed as name/value pairs. The following options are recognized: =over =item default_modifiers array_reference This argument is a reference to a list of default modifiers to be applied to the statement being parsed. See L L for the details. =item encoding name This argument is the name of the encoding of the regular expression. If specified, it is passed through to L<< PPIx::Regexp->new()|PPIx::Regexp/new >>. It also causes an C to be done on any parse content dumped. =item explain boolean If true, this option causes the C output of each object to be dumped. =item indent number This argument is the number of additional spaces to indent each level of the parse hierarchy. This is ignored if either the C or C argument is true. The default is 2. =item margin number This is the number of spaces to indent the top level of the parse hierarchy. This is ignored if the C argument is true. The default is zero. =item ordinal boolean If true, this option causes the C values of L objects to be dumped. =item perl_version boolean If true, this option causes the C and C values associated with each object dumped to be displayed. =item postderef boolean If true, postfix dereferences are recognized in code and interpolations. See the tokenizer's L for details. =item strict boolean This option is passed on to the parser, where it specifies whether the parse should assume C is in effect. The C<'strict'> pragma was introduced in Perl 5.22, and its documentation says that it is experimental, and that there is no commitment to backward compatibility. The same applies to the parse produced when this option is asserted. The default is false. =item significant boolean If true, this option causes only significant elements to be dumped. The default is false. =item test boolean If true, this option causes the output to be formatted as a regression test rather than as a straight dump. The output produced by asserting this option is explicitly undocumented, in the sense that the author reserves the right to change the generated output without notice of any kind. The default is false. =item tokens boolean If true, this option causes a dump of tokenizer output rather than of a full parse of the regular expression. This is forced true if the dump is of a L. The default is false. =item trace number If greater than zero, this option causes a trace of the parse. This option is unsupported in the sense that the author reserves the right to change it without notice. The default is zero. =item verbose number If greater than zero, this option causes additional information to be given about the elements found. This option is unsupported in the sense that the author reserves the right to change it without notice. The default is zero. =back If the thing to be dumped was a string, unrecognized arguments are passed to C<< PPIx::Regexp::Tokenizer->new() >>. Otherwise they are ignored. =cut { my %default = ( explain => 0, indent => 2, margin => 0, ordinal => 0, perl_version => 0, significant => 0, test => 0, tokens => 0, verbose => 0, ); sub new { my ( $class, $re, %args ) = @_; ref $class and $class = ref $class; my $self = { encoding => $args{encoding}, lister => undef, object => undef, source => $re, strict => $args{strict}, }; foreach my $key ( qw{ default_modifiers parse postderef } ) { exists $args{$key} and $self->{$key} = $args{$key}; } foreach my $key ( keys %default ) { $self->{$key} = exists $args{$key} ? delete $args{$key} : $default{$key}; } $self->{ordinal} ||= $self->{verbose}; if ( __instance( $re, 'PPIx::Regexp::Tokenizer' ) ) { $self->{object} = $re; $self->{tokens} = 1; } elsif ( __instance( $re, 'PPIx::Regexp::Element' ) ) { $self->{object} = $re; } elsif ( ref $re eq 'ARRAY' ) { $self->{object} = $re; } elsif ( ref $re && ! __instance( $re, 'PPI::Element' ) ) { croak "Do not know how to dump ", ref $re; } elsif ( $self->{tokens} ) { my $tokenizer_class = __choose_tokenizer_class( $re, \%args ) or croak 'Unsupported data type'; $self->{object} = $tokenizer_class->new( $re, %args ) or Carp::croak( $tokenizer_class->errstr() ); } else { $self->{object} = PPIx::Regexp->new( $re, %args ) or Carp::croak( PPIx::Regexp->errstr() ); } bless $self, $class; return $self; } } =head2 list print map { "$_\n" } $dumper->list(); This method produces an array containing the dump output, one line per element. The output has no left margin applied, and no newlines. =cut sub list { my ( $self ) = @_; my $lister = $self->{test} ? '__PPIX_DUMPER__test' : '__PPIX_DUMPER__dump'; ref $self->{object} eq 'ARRAY' and return ( map { $_->$lister( $self ) } @{ $self->{object} } ); return $self->{object}->$lister( $self ); } =head2 print $dumper->print(); This method simply prints the result of L to standard out. =cut sub print : method { ## no critic (ProhibitBuiltinHomonyms) my ( $self ) = @_; print $self->string(); return; } =head2 string print $dumper->string(); This method adds left margin and newlines to the output of L, concatenates the result into a single string, and returns that string. =cut sub string { my ( $self ) = @_; my $margin = ' ' x $self->{margin}; return join( '', map { $margin . $_ . "\n" } $self->list() ); } # quote a string. sub _safe { my ( $self, @args ) = @_; my @rslt; foreach my $item ( @args ) { if ( blessed( $item ) ) { $item = $self->encode( $item->content() ); } if ( ! defined $item ) { push @rslt, 'undef'; } elsif ( ref $item eq 'ARRAY' ) { push @rslt, join( ' ', '[', $self->_safe( @{ $item } ), ']' ); } elsif ( looks_like_number( $item ) ) { push @rslt, $item; } else { $item =~ s/ ( [\\'] ) /\\$1/smxg; push @rslt, "'$item'"; } } my $rslt = join( ', ', @rslt ); return $rslt } sub _safe_version { my ( undef, $version ) = @_; # Invocant unused return defined $version ? "'$version'" : 'undef'; } sub __nav { my ( $self, @args ) = @_; my $rslt = $self->_safe( @args ); $rslt =~ s/ ' (\w+) ' , /$1 =>/smxg; $rslt =~ s/ \[ \s+ \] /[]/smxg; $rslt =~ s/ \[ \s* ( \d+ ) \s* \] /$1/smxg; return $rslt; } sub _perl_version { my ( undef, $elem ) = @_; # Invocant unused return $elem->requirements_for_perl(); } sub _content { my ( $self, $elem, $dflt ) = @_; defined $dflt or $dflt = ''; defined $elem or return $dflt; if ( ref $elem eq 'ARRAY' ) { my $rslt = join '', map { $self->_content( $_ ) } grep { ! $self->{significant} || $_->significant() } @{ $elem }; return $rslt eq '' ? $dflt : $rslt; } blessed( $elem ) or return $dflt; return $self->encode( $elem->content() ); } sub _tokens_dump { my ( $self, $elem ) = @_; not $self->{significant} or $elem->significant() or return; my @rslt; foreach my $token ( $elem->tokens() ) { not $self->{significant} or $token->significant() or next; push @rslt, $token->__PPIX_DUMPER__dump( $self ); } return @rslt; } sub _format_default_modifiers { my ( $self, $subr, $elem ) = @_; my @arg = $self->_safe( $elem ); foreach my $attr ( qw{ default_modifiers parse postderef strict } ) { defined ( my $val = $self->{$attr} ) or next; 'ARRAY' eq ref $val and not @{ $val } and next; push @arg, "$attr => @{[ $self->_safe( $val ) ]}"; } return sprintf '%-8s( %s );', $subr, join ', ', @arg; } sub _format_modifiers_dump { my ( undef, $elem ) = @_; # Invocant unused my %mods = $elem->modifiers(); my @accum; $mods{match_semantics} and push @accum, 'match_semantics=' . delete $mods{match_semantics}; foreach my $modifier ( sort keys %mods ) { push @accum, $mods{$modifier} ? $modifier : "-$modifier"; } @accum and return join ' ', @accum; return; } sub _tokens_test { my ( $self, $elem ) = @_; not $self->{significant} or $elem->significant() or return; my @tokens = $elem->tokens(); my @rslt = ( $self->_format_default_modifiers( tokenize => $elem ), sprintf( 'count ( %d );', scalar @tokens ), ); my $inx = 0; foreach my $token ( @tokens ) { not $self->{significant} or $token->significant() or next; push @rslt, $token->__PPIX_DUMPER__test( $self, $inx++ ); } return @rslt; } sub PPIx::Regexp::Element::__PPIX_DUMPER__dump_explanation { my ( $self, undef, $line ) = @_; # $dumper unused my @expl = $self->explain() or return $line; 1 == @expl and return "$line\t$expl[0]"; wantarray or return sprintf "%s\t%s", $line, join '; ', @expl; ( my $blank = $line ) =~ s/\S/ /smxg; my @rslt; foreach my $splain ( @expl ) { push @rslt, "$line\t$splain"; $line = $blank; } return @rslt; } sub PPIx::Regexp::__PPIX_DUMPER__test { my ( $self, $dumper ) = @_; $dumper->{tokens} and return $dumper->_tokens_test( $self ); not $dumper->{significant} or $self->significant() or return; # my $parse = 'parse ( ' . $dumper->_safe( $self ) . ' );'; my $parse = $dumper->_format_default_modifiers( parse => $self ); my $fail = 'value ( failures => [], ' . $self->failures() . ' );'; # Note that we can not use SUPER in the following because SUPER goes # by the current package, not by the class of the object. my @rslt = PPIx::Regexp::Node::__PPIX_DUMPER__test( $self, $dumper ); # Get rid of the empty choose(); shift @rslt; return ( $parse, $fail, @rslt ); } sub PPIx::Regexp::Node::__PPIX_DUMPER__dump { my ( $self, $dumper ) = @_; $dumper->{tokens} and return $dumper->_tokens_dump( $self ); not $dumper->{significant} or $self->significant() or return; my @rslt = ref $self; $self->isa( 'PPIx::Regexp' ) and $rslt[-1] .= $dumper->{verbose} ? sprintf "\tfailures=%d\tmax_capture_number=%d", $self->failures(), $self->max_capture_number() : sprintf "\tfailures=%d", $self->failures(); $dumper->{perl_version} and $rslt[-1] .= "\t" . $dumper->_perl_version( $self ); if ( defined ( my $err = $self->error() ) ) { $rslt[-1] .= "\t$err"; } else { $dumper->{explain} and push @rslt, $self->__PPIX_DUMPER__dump_explanation( $dumper, pop @rslt ); } my $indent = ' ' x $dumper->{indent}; foreach my $elem ( $self->children() ) { push @rslt, map { $indent . $_ } $elem->__PPIX_DUMPER__dump( $dumper ); } return @rslt; } sub PPIx::Regexp::Node::__PPIX_DUMPER__test { my ( $self, $dumper ) = @_; not $dumper->{significant} or $self->significant() or return; my @rslt; @rslt = ( 'choose ( ' . $dumper->__nav( $self->nav() ) . ' );', 'class ( ' . $dumper->_safe( ref $self ) . ' );', 'count ( ' . scalar $self->children() . ' );', ); if ( defined( my $err = $self->error() ) ) { push @rslt, 'error ( ' . $dumper->_safe( $err ) . ' );'; } if ( $dumper->{perl_version} ) { foreach my $method ( qw{ perl_version_introduced perl_version_removed } ) { push @rslt, "value ( $method => [], " . $dumper->_safe_version( $self->$method() ) . ' );'; } } foreach my $elem ( $self->children() ) { push @rslt, $elem->__PPIX_DUMPER__test( $dumper ); } return @rslt; } sub _format_value { my ( $val ) = @_; defined $val or return 'undef'; $val =~ m/ \A [0-9]+ \z /smx and return $val; $val =~ s/ (?= [\\"] ) /\\/smxg; return qq{"$val"}; } { my %dflt = ( start => '???', type => '', finish => '???', ); sub PPIx::Regexp::Structure::__PPIX_DUMPER__dump { my ( $self, $dumper ) = @_; not $dumper->{significant} or $self->significant() or return; my @delim; foreach my $method ( qw{ start type finish } ) { my @elem = $self->$method(); push @delim, @elem ? $dumper->_content( \@elem ) : $dflt{$method}; } my @rslt = ( ref $self, "$delim[0]$delim[1] ... $delim[2]" ); $dumper->{perl_version} and push @rslt, $dumper->_perl_version( $self ); if ( $dumper->{verbose} ) { foreach my $method ( qw{ number name max_capture_number } ) { $self->can( $method ) or next; push @rslt, sprintf '%s=%s', $method, _format_value( $self->$method() ); } foreach my $method ( qw{ can_be_quantified is_quantifier } ) { ## is_case_sensitive $self->can( $method ) or next; $self->$method() and push @rslt, $method; } $self->isa( 'PPIx::Regexp::Structure::Modifier' ) and push @rslt, $dumper->_format_modifiers_dump( $self->type( 0 ) ); } foreach my $method ( 'start', undef, 'finish' ) { my $ele = defined $method ? $self->$method() : $self or next; if ( defined ( my $err = $ele->error() ) ) { push @rslt, $err; } } @rslt = ( join "\t", @rslt ); $dumper->{explain} and not defined $self->error() and push @rslt, $self->__PPIX_DUMPER__dump_explanation( $dumper, pop @rslt ); my $indent = ' ' x $dumper->{indent}; foreach my $elem ( $self->children() ) { push @rslt, map { $indent . $_ } $elem->__PPIX_DUMPER__dump( $dumper ); } return @rslt; } } sub PPIx::Regexp::Structure::__PPIX_DUMPER__test { my ( $self, $dumper ) = @_; not $dumper->{significant} or $self->significant() or return; my @nav = $self->nav(); my @rslt = ( 'choose ( ' . $dumper->__nav( @nav ) . ' );', 'class ( ' . $dumper->_safe( ref $self ) . ' );', 'count ( ' . scalar $self->children() . ' );', ); if ( $dumper->{verbose} ) { foreach my $method ( qw{ number name } ) { $self->can( $method ) or next; push @rslt, 'value ( ' . $method . ' => [], ' . $dumper->_safe( $self->$method() ) . ' );'; } } foreach my $method ( qw{ start type finish } ) { my @eles = $self->$method(); push @rslt, 'choose ( ' . $dumper->__nav( @nav, $method, [] ) . ' );', 'count ( ' . scalar @eles . ' );'; foreach my $inx ( 0 .. $#eles ) { my $elem = $eles[$inx]; push @rslt, 'choose ( ' . $dumper->__nav( @nav, $method, $inx ) . ' );', 'class ( ' . $dumper->_safe( ref $elem || $elem ) . ' );', 'content ( ' . $dumper->_safe( $elem ) . ' );'; } } foreach my $elem ( $self->children() ) { push @rslt, $elem->__PPIX_DUMPER__test( $dumper ); } return @rslt; } sub PPIx::Regexp::Tokenizer::__PPIX_DUMPER__dump { my ( $self, $dumper ) = @_; return $dumper->_tokens_dump( $self ); } sub PPIx::Regexp::Tokenizer::__PPIX_DUMPER__test { my ( $self, $dumper ) = @_; return $dumper->_tokens_test( $self ); } sub PPIx::Regexp::Token::__PPIX_DUMPER__dump { my ( $self, $dumper ) = @_; not $dumper->{significant} or $self->significant() or return; my @rslt = ( ref $self, $dumper->_safe( $self ) ); $dumper->{perl_version} and push @rslt, $dumper->_perl_version( $self ); if ( defined( my $err = $self->error() ) ) { return join "\t", @rslt, $err; } else { if ( $dumper->{ordinal} && $self->can( 'ordinal' ) && defined ( my $ord = $self->ordinal() ) ) { push @rslt, sprintf '0x%02x', $ord; } if ( $dumper->{verbose} ) { if ( $self->isa( 'PPIx::Regexp::Token::Reference' ) ) { foreach my $method ( qw{ absolute name number } ) { defined( my $val = $self->$method() ) or next; push @rslt, "$method=$val"; } } foreach my $method ( qw{ significant can_be_quantified is_quantifier } ) { ## is_case_sensitive $self->can( $method ) and $self->$method() and push @rslt, $method; } $self->can( 'ppi' ) and push @rslt, $self->ppi()->content(); if ( $self->isa( 'PPIx::Regexp::Token::Modifier' ) || $self->isa( 'PPIx::Regexp::Token::GroupType::Modifier' ) ) { push @rslt, $dumper->_format_modifiers_dump( $self ); } } @rslt = ( join "\t", @rslt ); $dumper->{explain} and push @rslt, $self->__PPIX_DUMPER__dump_explanation( $dumper, pop @rslt ); return @rslt; } } sub PPIx::Regexp::Token::__PPIX_DUMPER__test { my ( $self, $dumper, @nav ) = @_; not $dumper->{significant} or $self->significant() or return; @nav or @nav = $self->nav(); my @rslt = ( 'choose ( ' . join(', ', $dumper->__nav( @nav ) ) . ' );', 'class ( ' . $dumper->_safe( ref $self ) . ' );', 'content ( ' . $dumper->_safe( $self ) . ' );', ); if ( defined( my $err = $self->error() ) ) { push @rslt, 'error ( ' . $dumper->_safe( $err ) . ' );'; } else { if ( $dumper->{perl_version} ) { foreach my $method ( qw{ perl_version_introduced perl_version_removed } ) { push @rslt, "value ( $method => [], " . $dumper->_safe_version( $self->$method() ) . ' );'; } } if ( $dumper->{verbose} ) { foreach my $method ( qw{ significant can_be_quantified is_quantifier } ) { ## is_case_sensitive $self->can( $method ) or next; push @rslt, $self->$method() ? "true ( $method => [] );" : "false ( $method => [] );"; } $self->can( 'ppi' ) and push @rslt, "value ( ppi => [], " . $dumper->_safe( $self->ppi() ) . ' );'; } } return @rslt; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Element.pm000444000765000024 4373313237102475 17620 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Element - Base of the PPIx::Regexp hierarchy. =head1 SYNOPSIS No user-serviceable parts inside. =head1 INHERITANCE C is not descended from any other class. C is the parent of L and L. =head1 DESCRIPTION This class is the base of the L object hierarchy. It provides the same kind of navigational functionality that is provided by L. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Element; use strict; use warnings; use 5.006; use Carp; use List::Util qw{ max min }; use List::MoreUtils qw{ firstidx }; use PPIx::Regexp::Util qw{ __instance }; use Scalar::Util qw{ refaddr weaken }; use PPIx::Regexp::Constant qw{ FALSE LITERAL_LEFT_CURLY_REMOVED_PHASE_1 MINIMUM_PERL TOKEN_UNKNOWN TRUE }; our $VERSION = '0.055'; =head2 accepts_perl $token->accepts_perl( '5.020' ) and say 'This works under Perl 5.20'; This method returns a true value if the token is acceptable under the specified version of Perl, and a false value otherwise. Unless the token (or its contents) have been equivocated on, the result is simply what you would expect based on testing the results of L and L versus the given Perl version number. This method was added in version 0.051_01. =cut sub accepts_perl { my ( $self, $version ) = @_; foreach my $check ( $self->__perl_requirements() ) { $version < $check->{introduced} and next; defined $check->{removed} and $version >= $check->{removed} and next; return TRUE; } return FALSE; } # Return the Perl requirements, constructing if necessary. The # requirements are simply an array of hashes containing keys: # {introduced} - The Perl version introduced; # {removed} - The Perl version removed (or undef) # The requirements are evaluated by iterating through the array, # returning a true value if the version of Perl being tested falls # inside any of the half-open (on the right) intervals. sub __perl_requirements { my ( $self ) = @_; return @{ $self->{perl_requirements} ||= [ $self->__perl_requirements_setup() ] }; } # Construct the array returned by __perl_requirements(). sub __perl_requirements_setup { my ( $self ) = @_; return { introduced => $self->perl_version_introduced(), removed => $self->perl_version_removed(), }; } =head2 ancestor_of This method returns true if the object is an ancestor of the argument, and false otherwise. By the definition of this method, C<$self> is its own ancestor. =cut sub ancestor_of { my ( $self, $elem ) = @_; __instance( $elem, __PACKAGE__ ) or return; my $addr = refaddr( $self ); while ( $addr != refaddr( $elem ) ) { $elem = $elem->_parent() or return; } return 1; } =head2 can_be_quantified $token->can_be_quantified() and print "This element can be quantified.\n"; This method returns true if the element can be quantified. =cut sub can_be_quantified { return 1; } =head2 class This method returns the class name of the element. It is the same as C. =cut sub class { my ( $self ) = @_; return ref $self; } =head2 comment This method returns true if the element is a comment and false otherwise. =cut sub comment { return; } =head2 content This method returns the content of the element. =cut sub content { return; } =head2 descendant_of This method returns true if the object is a descendant of the argument, and false otherwise. By the definition of this method, C<$self> is its own descendant. =cut sub descendant_of { my ( $self, $node ) = @_; __instance( $node, __PACKAGE__ ) or return; return $node->ancestor_of( $self ); } =head2 explain This method returns a brief explanation of what the element does. The return will be either a string or C in scalar context, but may be multiple values or an empty array in list context. This method should be considered experimental. What it returns may change without notice as my understanding of what all the pieces/parts of a Perl regular expression evolves. The worst case is that it will prove entirely infeasible to implement satisfactorily, in which case it will be put through a deprecation cycle and retracted. =cut sub explain { my ( $self ) = @_; my $explanation = $self->__explanation(); my $content = $self->content(); if ( my $main = $self->main_structure() ) { my $delim = $main->delimiters(); $delim = qr{ \\ (?= [\Q$delim\E] ) }smx; $content =~ s/$delim//smxg; } if ( defined( my $splain = $explanation->{$content} ) ) { return $splain; } return $self->__no_explanation(); } # Return explanation hash sub __explanation { $PPIx::Regexp::NO_EXPLANATION_FATAL and confess 'Neither explain() nor __explanation() overridden'; return {}; } # Called if no explanation available sub __no_explanation { ## my ( $self ) = @_; # Invocant unused my $msg = sprintf q; $PPIx::Regexp::NO_EXPLANATION_FATAL and confess $msg; return $msg; } =head2 error say $token->error(); If an element is one of the classes that represents a parse error, this method B return a brief message saying why. Otherwise it will return C. =cut sub error { my ( $self ) = @_; return $self->{error}; } =head2 in_regex_set This method returns a true value if the invocant is contained in an extended bracketed character class (also known as a regex set), and a false value otherwise. This method returns true if the invocant is a L. =cut sub in_regex_set { my ( $self ) = @_; my $ele = $self; while ( 1 ) { $ele->isa( 'PPIx::Regexp::Structure::RegexSet' ) and return 1; $ele = $ele->parent() or last; } return 0; } =head2 is_quantifier $token->is_quantifier() and print "This element is a quantifier.\n"; This method returns true if the element is a quantifier. You can not tell this from the element's class, because a right curly bracket may represent a quantifier for the purposes of figuring out whether a greediness token is possible. =cut sub is_quantifier { return; } =head2 main_structure This method returns the L that contains the element. In practice this will be a L or a L, If the element is not contained in any such structure, C is returned. This will happen if the element is a L or one of its immediate children. =cut sub main_structure { my ( $self ) = @_; while ( $self = $self->parent() and not $self->isa( 'PPIx::Regexp::Structure::Main' ) ) { } return $self; } =head2 modifier_asserted $token->modifier_asserted( 'i' ) and print "Matched without regard to case.\n"; This method returns true if the given modifier is in effect for the element, and false otherwise. What it does is to walk backwards from the element until it finds a modifier object that specifies the modifier, whether asserted or negated. and returns the specified value. If nobody specifies the modifier, it returns C. This method will not work reliably if called on tokenizer output. =cut sub modifier_asserted { my ( $self, $modifier ) = @_; defined $modifier or croak 'Modifier must be defined'; my $elem = $self; while ( $elem ) { if ( $elem->can( '__ducktype_modifier_asserted' ) ) { my $val; defined( $val = $elem->__ducktype_modifier_asserted( $modifier ) ) and return $val; } if ( my $prev = $elem->sprevious_sibling() ) { $elem = $prev; } else { $elem = $elem->parent(); } } return; } =head2 next_sibling This method returns the element's next sibling, or nothing if there is none. =cut sub next_sibling { my ( $self ) = @_; my ( $method, $inx ) = $self->_my_inx() or return; return $self->_parent()->$method( $inx + 1 ); } =head2 parent This method returns the parent of the element, or undef if there is none. =cut sub parent { my ( $self ) = @_; return $self->_parent(); } =head2 perl_version_introduced This method returns the version of Perl in which the element was introduced. This will be at least 5.000. Before 5.006 I am relying on the F, F, and F documentation, since I have been unable to build earlier Perls. Since I have found no documentation before 5.003, I assume that anything found in 5.003 is also in 5.000. Since this all depends on my ability to read and understand masses of documentation, the results of this method should be viewed with caution, if not downright skepticism. There are also cases which are ambiguous in various ways. For those see the L documentation, particularly L. Very occasionally, a construct will be removed and then added back. If this happens, this method will return the B version in which the construct appeared. For the known instances of this, see the L documentation, particularly L. =cut sub perl_version_introduced { return MINIMUM_PERL; } =head2 perl_version_removed This method returns the version of Perl in which the element was removed. If the element is still valid the return is C. All the I to L apply here also, though perhaps less severely since although many features have been introduced since 5.0, few have been removed. Very occasionally, a construct will be removed and then added back. If this happens, this method will return the C if the construct is present in the highest-numbered version of Perl (whether production or development), or the version after the highest-numbered version in which it appeared otherwise. For the known instances of this, see the L documentation, particularly L. =cut sub perl_version_removed { return undef; ## no critic (ProhibitExplicitReturnUndef) } =head2 previous_sibling This method returns the element's previous sibling, or nothing if there is none. =cut sub previous_sibling { my ( $self ) = @_; my ( $method, $inx ) = $self->_my_inx() or return; $inx or return; return $self->_parent()->$method( $inx - 1 ); } =head2 requirements_for_perl say $token->requirements_for_perl(); This method returns a string representing the Perl requirements for a given module. This should only be used for informational purposes, as the format of the string may be subject to change. This method was added in version 0.051_01. =cut sub requirements_for_perl { my ( $self ) = @_; my @req; foreach my $r ( @{ $self->__structured_requirements_for_perl( [] ) } ) { push @req, defined $r->{removed} ? "$r->{introduced} <= \$] < $r->{removed}" : "$r->{introduced} <= \$]"; } return join ' || ', @req; } =head2 scontent This method returns the significant content of the element. That is, if called on the parse of C<'/ f u b a r /x'>, it returns C<'/fubar/x'>. If the invocant contains no insignificant elements, it is the same as L. If called on an insignificant element, it returns nothing -- that is, C in scalar context, and an empty list in list context. This method was inspired by jb's question on Perl Monks about stripping comments and white space from a regular expression: L This method was added in version 0.053_01 =cut sub scontent { return; } =head2 significant This method returns true if the element is significant and false otherwise. =cut sub significant { return 1; } =head2 snext_sibling This method returns the element's next significant sibling, or nothing if there is none. =cut sub snext_sibling { my ( $self ) = @_; my $sib = $self; while ( defined ( $sib = $sib->next_sibling() ) ) { $sib->significant() and return $sib; } return; } =head2 sprevious_sibling This method returns the element's previous significant sibling, or nothing if there is none. =cut sub sprevious_sibling { my ( $self ) = @_; my $sib = $self; while ( defined ( $sib = $sib->previous_sibling() ) ) { $sib->significant() and return $sib; } return; } # NOTE: This method is to be used ONLY for requirements_for_perl(). I # _may_ eventually expose it, but at the moment I do not consider it # stable. The exposure would be # sub structured_requirements_for_perl { # my ( $self ) = @_; # return $self->__structured_requirements_for_perl( [] ); # } sub __structured_requirements_for_perl { my ( $self, $rslt ) = @_; if ( @{ $rslt } ) { my @merged; foreach my $left ( $self->__perl_requirements() ) { foreach my $right ( @{ $rslt } ) { my $min = max( $left->{introduced}, $right->{introduced} ); my $max = defined $left->{removed} ? defined $right->{removed} ? min( $left->{removed}, $right->{removed} ) : $left->{removed} : $right->{removed}; defined $max and $max <= $min and next; push @merged, { introduced => $min, removed => $max, }; } } @{ $rslt } = @merged; } else { @{ $rslt } = $self->__perl_requirements(); } return $rslt; } =head2 tokens This method returns all tokens contained in the element. =cut sub tokens { my ( $self ) = @_; return $self; } =head2 top This method returns the top of the hierarchy. =cut sub top { my ( $self ) = @_; my $kid = $self; while ( defined ( my $parent = $kid->_parent() ) ) { $kid = $parent; } return $kid; } =head2 unescaped_content This method returns the content of the element, unescaped. =cut sub unescaped_content { return; } =head2 whitespace This method returns true if the element is whitespace and false otherwise. =cut sub whitespace { return; } =head2 nav This method returns navigation information from the top of the hierarchy to this node. The return is a list of names of methods and references to their argument lists. The idea is that given C<$elem> which is somewhere under C<$top>, my @nav = $elem->nav(); my $obj = $top; while ( @nav ) { my $method = shift @nav; my $args = shift @nav; $obj = $obj->$method( @{ $args } ) or die; } # At this point, $obj should contain the same object # as $elem. =cut sub nav { my ( $self ) = @_; __instance( $self, __PACKAGE__ ) or return; # We do not use $self->parent() here because PPIx::Regexp overrides # this to return the (possibly) PPI object that initiated us. my $parent = $self->_parent() or return; return ( $parent->nav(), $parent->__nav( $self ) ); } # Find our location and index among the parent's children. If not found, # just returns. { my %method_map = ( children => 'child', ); sub _my_inx { my ( $self ) = @_; my $parent = $self->_parent() or return; my $addr = refaddr( $self ); foreach my $method ( qw{ children start type finish } ) { $parent->can( $method ) or next; my $inx = firstidx { refaddr $_ == $addr } $parent->$method(); $inx < 0 and next; return ( $method_map{$method} || $method, $inx ); } return; } } { my %parent; # no-argument form returns the parent; one-argument sets it. sub _parent { my ( $self, @arg ) = @_; my $addr = refaddr( $self ); if ( @arg ) { my $parent = shift @arg; if ( defined $parent ) { __instance( $parent, __PACKAGE__ ) or return; weaken( $parent{$addr} = $parent ); } else { delete $parent{$addr}; } } return $parent{$addr}; } sub __parent_keys { return scalar keys %parent; } } # Bless into TOKEN_UNKNOWN, record error message, return 1. sub __error { my ( $self, $msg ) = @_; defined $msg or $msg = 'Was ' . ref $self; $self->{error} = $msg; bless $self, TOKEN_UNKNOWN; return 1; } # This huge kluge is required by # https://rt.perl.org/Ticket/Display.html?id=128213 which means the # deprecation will be done in at least two separate phases. It exists # for the use of PPIx::Regexp::Token::Literal->perl_version_removed, and # MUST NOT be called by any other code. # Note that the perldelta for 5.25.1 and 5.26.0 do not acknowledge tha # phased deprecation, and pretend that everything was done on the phase # 1 schedule. This appears to be deliberate per # https://rt.perl.org/Ticket/Display.html?id=131352 sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_REMOVED_PHASE_1; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( undef, $number ) = @_; # Invocant unused return $number; } # Called by the lexer to rebless sub __PPIX_ELEM__rebless { my ( $class, $self ) = @_; # %arg unused $self ||= {}; bless $self, $class; delete $self->{error}; defined $self->{error} and return 1; delete $self->{error}; return 0; } sub DESTROY { $_[0]->_parent( undef ); return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Lexer.pm000444000765000024 3720713237102475 17305 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Lexer - Assemble tokenizer output. =head1 SYNOPSIS use PPIx::Regexp::Lexer; use PPIx::Regexp::Dumper; my $lex = PPIx::Regexp::Lexer->new('qr{foo}smx'); my $dmp = PPIx::Regexp::Dumper->new( $lex ); $dmp->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class takes the token stream generated by L and generates the parse tree. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Lexer; use strict; use warnings; use base qw{ PPIx::Regexp::Support }; use Carp qw{ confess }; use PPIx::Regexp::Constant qw{ TOKEN_LITERAL TOKEN_UNKNOWN }; use PPIx::Regexp::Node::Range (); use PPIx::Regexp::Node::Unknown (); use PPIx::Regexp::Structure (); use PPIx::Regexp::Structure::Assertion (); use PPIx::Regexp::Structure::BranchReset (); use PPIx::Regexp::Structure::Code (); use PPIx::Regexp::Structure::Capture (); use PPIx::Regexp::Structure::CharClass (); use PPIx::Regexp::Structure::Subexpression (); use PPIx::Regexp::Structure::Main (); use PPIx::Regexp::Structure::Modifier (); use PPIx::Regexp::Structure::NamedCapture (); use PPIx::Regexp::Structure::Quantifier (); use PPIx::Regexp::Structure::Regexp (); use PPIx::Regexp::Structure::RegexSet (); use PPIx::Regexp::Structure::Replacement (); use PPIx::Regexp::Structure::Script_Run (); use PPIx::Regexp::Structure::Switch (); use PPIx::Regexp::Structure::Unknown (); use PPIx::Regexp::Token::Unmatched (); use PPIx::Regexp::Tokenizer (); use PPIx::Regexp::Util qw{ __choose_tokenizer_class __instance }; our $VERSION = '0.055'; =head2 new This method instantiates the lexer. It takes as its argument either a L or the text to be parsed. In the latter case the tokenizer is instantiated from the text. Any optional name/value pairs after the first argument are passed to the tokenizer, which interprets them or not as the case may be. =cut { my $errstr; sub new { my ( $class, $tokenizer, %args ) = @_; ref $class and $class = ref $class; unless ( __instance( $tokenizer, 'PPIx::Regexp::Tokenizer' ) ) { my $tokenizer_class = __choose_tokenizer_class( $tokenizer, \%args ) or do { $errstr = 'Data not supported'; return; }; $tokenizer = $tokenizer_class->new( $tokenizer, %args ) or do { $errstr = $tokenizer_class->errstr(); return; }; } my $self = { deferred => [], # Deferred tokens failures => 0, strict => $args{strict}, tokenizer => $tokenizer, }; bless $self, $class; return $self; } sub errstr { return $errstr; } } =head2 errstr This method returns the error string from the last attempt to instantiate a C. If the last attempt succeeded, the error will be C. =cut # Defined above =head2 failures print $lexer->failures(), " parse failures\n"; This method returns the number of parse failures encountered. A parse failure is either a tokenization failure (see L<< PPIx::Regexp::Tokenizer->failures()|PPIx::Regexp::Tokenizer/failures >>) or a structural error. =cut sub failures { my ( $self ) = @_; return $self->{failures}; } =head2 lex This method lexes the tokens in the text, and returns the lexed list of elements. =cut sub lex { my ( $self ) = @_; my @content; $self->{failures} = 0; # Accept everything up to the first delimiter. my $kind; # Initial PPIx::Regexp::Token::Structure { my $token = $self->_get_token() or return $self->_finalize( @content ); $token->isa( 'PPIx::Regexp::Token::Delimiter' ) or do { not $kind and $token->isa( 'PPIx::Regexp::Token::Structure' ) and $kind = $token; push @content, $token; redo; }; $self->_unget_token( $token ); } my ( $part_0_class, $part_1_class ) = $self->{tokenizer}->__part_classes(); # Accept the first delimited structure. push @content, ( my $part_0 = $self->_get_delimited( $part_0_class ) ); # If we are a substitution ... if ( defined $part_1_class ) { # Accept any insignificant stuff. while ( my $token = $self->_get_token() ) { if ( $token->significant() ) { $self->_unget_token( $token ); last; } else { push @content, $token; } } # Figure out if we should expect an opening bracket. my $expect_open_bracket = $self->close_bracket( $part_0->start( 0 ) ) || 0; # Accept the next delimited structure. push @content, $self->_get_delimited( $part_1_class, $expect_open_bracket, ); } # Accept the modifiers (we hope!) plus any trailing white space. while ( my $token = $self->_get_token() ) { push @content, $token; } # Let all the elements finalize themselves, recording any additional # errors as they do so. $self->_finalize( @content ); # If we found a regular expression (and we should have done so) ... if ( $part_0 && $part_0->can( 'max_capture_number' ) ) { # TODO the above line is really ugly. I'm wondering about # string implementations like: # * return a $part_0_class of undef (but that complicates the # lexing of the structure itself); # * hang this logic on the tokenizer somehow (where it seems out # of place) # * hang this logic on PPIx::Regexp::Structure::Regexp and # ::Replacement. # I also need to figure out how to make \n backreferences come # out as literals. Maybe that is a job best done by the # tokenizer. # Retrieve the maximum capture group. my $max_capture = $part_0->max_capture_number(); # Hashify the known capture names my $capture_name = { map { $_ => 1 } $part_0->capture_names(), }; # For all the backreferences found foreach my $elem ( @{ $part_0->find( 'PPIx::Regexp::Token::Backreference' ) || [] } ) { # Rebless them as needed, recording any errors found. $self->{failures} += $elem->__PPIX_LEXER__rebless( capture_name => $capture_name, max_capture => $max_capture, ); } } return @content; } =head2 strict This method returns true or false based on the value of the C<'strict'> argument to C. =cut sub strict { my ( $self ) = @_; return $self->{strict}; } # Finalize the content array, updating the parse failures count as we # go. sub _finalize { my ( $self, @content ) = @_; foreach my $elem ( @content ) { $self->{failures} += $elem->__PPIX_LEXER__finalize( $self ); } defined wantarray and return @content; return; } { my %bracket = ( '{' => '}', '(' => ')', '[' => ']', '(?[' => '])', ## '<' => '>', ); my %unclosed = ( '{' => '_recover_curly', ); sub _get_delimited { my ( $self, $class, $expect_open_bracket ) = @_; defined $expect_open_bracket or $expect_open_bracket = 1; my @rslt; $self->{_rslt} = \@rslt; if ( $expect_open_bracket ) { if ( my $token = $self->_get_token() ) { push @rslt, []; if ( $token->isa( 'PPIx::Regexp::Token::Delimiter' ) ) { push @{ $rslt[-1] }, '', $token; } else { push @{ $rslt[-1] }, '', undef; $self->_unget_token( $token ); } } else { return; } } else { push @rslt, [ '', undef ]; } while ( my $token = $self->_get_token() ) { if ( $token->isa( 'PPIx::Regexp::Token::Delimiter' ) ) { $self->_unget_token( $token ); last; } if ( $token->isa( 'PPIx::Regexp::Token::Structure' ) ) { my $content = $token->content(); if ( my $finish = $bracket{$content} ) { # Open bracket push @rslt, [ $finish, $token ]; } elsif ( $content eq $rslt[-1][0] ) { # Matched close bracket $self->_make_node( $token ); } elsif ( $content ne ')' ) { # If the close bracket is not a parenthesis, it becomes # a literal. TOKEN_LITERAL->__PPIX_ELEM__rebless( $token ); push @{ $rslt[-1] }, $token; } elsif ( $content eq ')' and @rslt > 1 # Ignore enclosing delimiter and my $recover = $unclosed{$rslt[-1][1]->content()} ) { # If the close bracket is a parenthesis and there is a # recovery procedure, we use it. $self->$recover( $token ); } else { # Unmatched close with no recovery. $self->{failures}++; PPIx::Regexp::Token::Unmatched-> __PPIX_ELEM__rebless( $token ); push @{ $rslt[-1] }, $token; } } else { push @{ $rslt[-1] }, $token; } # We have to hand-roll the Range object. if ( __instance( $rslt[-1][-2], 'PPIx::Regexp::Token::Operator' ) && $rslt[-1][-2]->content() eq '-' && $rslt[-1][0] eq ']' # It's a character class ) { my @tokens = splice @{ $rslt[-1] }, -3; push @{ $rslt[-1] }, PPIx::Regexp::Node::Range->__new( @tokens ); } } while ( @rslt > 1 ) { if ( my $recover = $unclosed{$rslt[-1][1]->content()} ) { $self->$recover(); } else { $self->{failures}++; $self->_make_node( undef ); } } if ( @rslt == 1 ) { my @last = @{ pop @rslt }; shift @last; push @last, $self->_get_token(); return $class->__new( @last ); } else { confess "Missing data"; } } } # $token = $self->_get_token(); # # This method returns the next token from the tokenizer. sub _get_token { my ( $self ) = @_; if ( @{ $self->{deferred} } ) { return shift @{ $self->{deferred} }; } my $token = $self->{tokenizer}->next_token() or return; return $token; } { my %handler = ( '(' => '_round', '[' => '_square', '{' => '_curly', '(?[' => '_regex_set', ); sub _make_node { my ( $self, $token ) = @_; my @args = @{ pop @{ $self->{_rslt} } }; shift @args; push @args, $token; my @node; if ( my $method = $handler{ $args[0]->content() } ) { @node = $self->$method( \@args ); } @node or @node = PPIx::Regexp::Structure->__new( @args ); push @{ $self->{_rslt}[-1] }, @node; return; } } # Called as $self->$method( ... ) in _make_node(), above sub _curly { ## no critic (ProhibitUnusedPrivateSubroutines) my ( $self, $args ) = @_; if ( $args->[-1] && $args->[-1]->is_quantifier() ) { # If the tokenizer has marked the right curly as a quantifier, # make the whole thing a quantifier structure. return PPIx::Regexp::Structure::Quantifier->__new( @{ $args } ); } elsif ( $args->[-1] ) { # If there is a right curly but it is not a quantifier, # make both curlys into literals. foreach my $inx ( 0, -1 ) { TOKEN_LITERAL->__PPIX_ELEM__rebless( $args->[$inx] ); } # Try to recover possible quantifiers not recognized because we # thought this was a structure. $self->_recover_curly_quantifiers( $args ); return @{ $args }; } else { # If there is no right curly, just make a generic structure # TODO maybe this should be something else? return PPIx::Regexp::Structure->__new( @{ $args } ); } } # Recover from an unclosed left curly. # Called as $self->$revover( ... ) in _get_delimited, above sub _recover_curly { ## no critic (ProhibitUnusedPrivateSubroutines) my ( $self, $token ) = @_; # Get all the stuff we have accumulated for this curly. my @content = @{ pop @{ $self->{_rslt} } }; # Lose the right bracket, which we have already failed to match. shift @content; # Rebless the left curly appropriately if ( $self->{_rslt}[0][-1]->isa( 'PPIx::Regexp::Token::Assertion' ) && q<\b> eq $self->{_rslt}[0][-1]->content() ) { # If following \b, it becomes an unknown. TOKEN_UNKNOWN->__PPIX_ELEM__rebless( $content[0], error => 'Unterminated bound type', ); } else { # Rebless the left curly to a literal. TOKEN_LITERAL->__PPIX_ELEM__rebless( $content[0] ); } # Try to recover possible quantifiers not recognized because we # thought this was a structure. $self->_recover_curly_quantifiers( \@content ); # Shove the curly and its putative contents into whatever structure # we have going. # The checks are to try to trap things like RT 56864, though on # further reflection it turned out that you could get here with an # empty $self->{_rslt} on things like 'm{)}'. This one did not get # made into an RT ticket, but was fixed by not calling the recovery # code if $self->{_rslt} contained only the enclosing delimiters. 'ARRAY' eq ref $self->{_rslt} or confess 'Programming error - $self->{_rslt} not array ref, ', "parsing '", $self->{tokenizer}->content(), "' at ", $token->content(); @{ $self->{_rslt} } or confess 'Programming error - $self->{_rslt} empty, ', "parsing '", $self->{tokenizer}->content(), "' at ", $token->content(); push @{ $self->{_rslt}[-1] }, @content; # Shove the mismatched delimiter back into the input so we can have # another crack at it. $token and $self->_unget_token( $token ); # We gone. return; } sub _recover_curly_quantifiers { my ( undef, $args ) = @_; # Invocant unused if ( __instance( $args->[0], TOKEN_LITERAL ) && __instance( $args->[1], TOKEN_UNKNOWN ) && PPIx::Regexp::Token::Quantifier->could_be_quantifier( $args->[1]->content() ) ) { PPIx::Regexp::Token::Quantifier-> __PPIX_ELEM__rebless( $args->[1] ); if ( __instance( $args->[2], TOKEN_UNKNOWN ) && PPIx::Regexp::Token::Greediness->could_be_greediness( $args->[2]->content() ) ) { PPIx::Regexp::Token::Greediness ->__PPIX_ELEM__rebless( $args->[2] ); } } return; } sub _in_regex_set { my ( $self ) = @_; foreach my $stack_entry ( reverse @{ $self->{_rslt} } ) { $stack_entry->[0] eq '])' and return 1; } return 0; } # Called as $self->$method( ... ) in _make_node(), above sub _round { ## no critic (ProhibitUnusedPrivateSubroutines) my ( $self, $args ) = @_; # If we're inside a regex set, parens do not capture. $self->_in_regex_set() and return PPIx::Regexp::Structure->__new( @{ $args } ); # If /n is asserted, parens do not capture. $self->{tokenizer}->modifier( 'n' ) and return PPIx::Regexp::Structure->__new( @{ $args } ); # The instantiator will rebless based on the first token if need be. return PPIx::Regexp::Structure::Capture->__new( @{ $args } ); } # Called as $self->$method( ... ) in _make_node(), above sub _square { ## no critic (ProhibitUnusedPrivateSubroutines) my ( undef, $args ) = @_; # Invocant unused return PPIx::Regexp::Structure::CharClass->__new( @{ $args } ); } # Called as $self->$method( ... ) in _make_node(), above sub _regex_set { ## no critic (ProhibitUnusedPrivateSubroutines) my ( undef, $args ) = @_; # Invocant unused return PPIx::Regexp::Structure::RegexSet->__new( @{ $args } ); } # $self->_unget_token( $token ); # # This method caches its argument so that it will be returned by # the next call to C<_get_token()>. If more than one argument is # passed, they will be returned in the order given; that is, # _unget_token/_get_token work like unshift/shift. sub _unget_token { my ( $self, @args ) = @_; unshift @{ $self->{deferred} }, @args; return $self; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Node.pm000444000765000024 2722413237102475 17111 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Node - Represent a container =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(foo)}' )->print(); =head1 INHERITANCE C is a L. C is the parent of L, L and L. =head1 DESCRIPTION This class represents a structural element that contains other classes. It is an abstract class, not instantiated by the lexer. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Node; use strict; use warnings; use base qw{ PPIx::Regexp::Element }; use Carp; use List::Util qw{ max }; use PPIx::Regexp::Constant qw{ FALSE MINIMUM_PERL NODE_UNKNOWN TRUE }; use PPIx::Regexp::Util qw{ __instance }; use Scalar::Util qw{ refaddr }; our $VERSION = '0.055'; use constant ELEMENT_UNKNOWN => NODE_UNKNOWN; sub __new { my ( $class, @children ) = @_; ref $class and $class = ref $class; foreach my $elem ( @children ) { __instance( $elem, 'PPIx::Regexp::Element' ) or return; } my $self = { children => \@children, }; bless $self, $class; foreach my $elem ( @children ) { $elem->_parent( $self ); } return $self; } sub accepts_perl { my ( $self, $version ) = @_; foreach my $elem ( $self->elements() ) { $elem->accepts_perl( $version ) or return FALSE; } return TRUE; } # NOTE: this method is to be used ONLY for requirements_for_perl(). See # PPIx::Regexp::Element for exposure plans. IF it is exposed, that is # where it will be documented. sub __structured_requirements_for_perl { my ( $self, $rslt ) = @_; foreach my $elem ( $self->elements() ) { $elem->__structured_requirements_for_perl( $rslt ); } return $rslt; } =head2 child my $kid = $node->child( 0 ); This method returns the child at the given index. The indices start from zero, and negative indices are from the end of the list, so that C<< $node->child( -1 ) >> returns the last child of the node. =cut sub child { my ( $self, $inx ) = @_; defined $inx or $inx = 0; return $self->{children}[$inx]; } =head2 children This method returns the children of the Node. If called in scalar context it returns the number of children. =cut sub children { my ( $self ) = @_; return @{ $self->{children} }; } =head2 contains print $node->contains( $elem ) ? "yes\n" : "no\n"; This method returns true if the given element is contained in the node, or false otherwise. =cut sub contains { my ( $self, $elem ) = @_; __instance( $elem, 'PPIx::Regexp::Element' ) or return; my $addr = refaddr( $self ); while ( $elem = $elem->parent() ) { $addr == refaddr( $elem ) and return 1; } return; } sub content { my ( $self ) = @_; return join( '', map{ $_->content() } $self->elements() ); } =head2 elements This method returns the elements in the Node. For a C proper, it is the same as C. =cut { no warnings qw{ once }; *elements = \&children; } =head2 find my $rslt = $node->find( 'PPIx::Regexp::Token::Literal' ); my $rslt = $node->find( 'Token::Literal' ); my $rslt = $node->find( sub { return $_[1]->isa( 'PPIx::Regexp::Token::Literal' ) && $_[1]->ordinal < ord(' '); } ); This method finds things. If given a string as argument, it is assumed to be a class name (possibly without the leading 'PPIx::Regexp::'), and all elements of the given class are found. If given a code reference, that code reference is called once for each element, and passed C<$self> and the element. The code should return true to accept the element, false to reject it, and ( for subclasses of C) C to prevent recursion into the node. If the code throws an exception, you get nothing back from this method. Either way, the return is a reference to the list of things found, a false (but defined) value if nothing was found, or C if an error occurred. =cut sub _find_routine { my ( $want ) = @_; ref $want eq 'CODE' and return $want; ref $want and return; $want =~ m/ \A PPIx::Regexp:: /smx or $want = 'PPIx::Regexp::' . $want; return sub { return __instance( $_[1], $want ) ? 1 : 0; }; } sub find { my ( $self, $want ) = @_; $want = _find_routine( $want ) or return; my @found; # We use a recursion to find what we want. PPI::Node uses an # iteration. foreach my $elem ( $self->elements() ) { my $rslt = eval { $want->( $self, $elem ) } and push @found, $elem; $@ and return; __instance( $elem, 'PPIx::Regexp::Node' ) or next; defined $rslt or next; $rslt = $elem->find( $want ) and push @found, @{ $rslt }; } return @found ? \@found : 0; } =head2 find_parents my $rslt = $node->find_parents( sub { return $_[1]->isa( 'PPIx::Regexp::Token::Operator' ) && $_[1]->content() eq '|'; } ); This convenience method takes the same arguments as C, but instead of the found objects themselves returns their parents. No parent will appear more than once in the output. This method returns a reference to the array of parents if any were found. If no parents were found the return is false but defined. If an error occurred the return is C. =cut sub find_parents { my ( $self, $want ) = @_; my $found; $found = $self->find( $want ) or return $found; my %parents; my @rslt; foreach my $elem ( @{ $found } ) { my $dad = $elem->parent() or next; $parents{ refaddr( $dad ) }++ or push @rslt, $dad; } return \@rslt; } =head2 find_first This method has the same arguments as L, but returns either a reference to the first element found, a false (but defined) value if no elements were found, or C if an error occurred. =cut sub find_first { my ( $self, $want ) = @_; $want = _find_routine( $want ) or return; # We use a recursion to find what we want. PPI::Node uses an # iteration. foreach my $elem ( $self->elements() ) { my $rslt = eval { $want->( $self, $elem ) } and return $elem; $@ and return; __instance( $elem, 'PPIx::Regexp::Node' ) or next; defined $rslt or next; defined( $rslt = $elem->find_first( $want ) ) or return; $rslt and return $rslt; } return 0; } =head2 first_element This method returns the first element in the node. =cut sub first_element { my ( $self ) = @_; return $self->{children}[0]; } =head2 last_element This method returns the last element in the node. =cut sub last_element { my ( $self ) = @_; return $self->{children}[-1]; } =head2 perl_version_introduced This method returns the maximum value of C returned by any of its elements. In other words, it returns the minimum version of Perl under which this node is valid. If there are no elements, 5.000 is returned, since that is the minimum value of Perl supported by this package. =cut sub perl_version_introduced { my ( $self ) = @_; return max( grep { defined $_ } MINIMUM_PERL, $self->{perl_version_introduced}, map { $_->perl_version_introduced() } $self->elements() ); } =head2 perl_version_removed This method returns the minimum defined value of C returned by any of the node's elements. In other words, it returns the lowest version of Perl in which this node is C valid. If there are no elements, or if no element has a defined C, C is returned. =cut sub perl_version_removed { my ( $self ) = @_; my $max; foreach my $elem ( $self->elements() ) { if ( defined ( my $ver = $elem->perl_version_removed() ) ) { if ( defined $max ) { $ver < $max and $max = $ver; } else { $max = $ver; } } } return $max; } =head2 schild This method returns the significant child at the given index; that is, C<< $node->schild(0) >> returns the first significant child, C<< $node->schild(1) >> returns the second significant child, and so on. Negative indices count from the end. =cut sub schild { my ( $self, $inx ) = @_; defined $inx or $inx = 0; my $kids = $self->{children}; if ( $inx >= 0 ) { my $loc = 0; while ( exists $kids->[$loc] ) { $kids->[$loc]->significant() or next; --$inx >= 0 and next; return $kids->[$loc]; } continue { $loc++; } } else { my $loc = -1; while ( exists $kids->[$loc] ) { $kids->[$loc]->significant() or next; $inx++ < -1 and next; return $kids->[$loc]; } continue { --$loc; } } return; } =head2 schildren This method returns the significant children of the node. =cut sub schildren { my ( $self ) = @_; if ( wantarray ) { return ( grep { $_->significant() } @{ $self->{children} } ); } elsif ( defined wantarray ) { my $kids = 0; foreach ( @{ $self->{children} } ) { $_->significant() and $kids++; } return $kids; } else { return; } } sub scontent { my ( $self ) = @_; # As of the invention of this method all nodes are significant, so # the following statement is pure paranoia on my part. -- TRW $self->significant() or return; # This needs to be elements(), not children() or schildren() -- or # selements() if that is ever invented. Not children() or # schildren() because those ignore the delimiters. Not selements() # (if that ever comes to pass) because scontent() has to make the # significance check, so selements() would be wasted effort. return join( '', map{ $_->scontent() } $self->elements() ); } sub tokens { my ( $self ) = @_; return ( map { $_->tokens() } $self->elements() ); } sub unescaped_content { my ( $self ) = @_; return join '', map { $_->unescaped_content() } $self->elements(); } # Help for nav(); sub __nav { my ( $self, $child ) = @_; refaddr( $child->parent() ) == refaddr( $self ) or return; my ( $method, $inx ) = $child->_my_inx() or return; return ( $method => [ $inx ] ); } sub __error { my ( $self, $msg, %arg ) = @_; defined $msg or $msg = 'Was class ' . ref $self; $self->{error} = $msg; bless $self, $self->ELEMENT_UNKNOWN(); foreach my $key ( keys %arg ) { $self->{$key} = $arg{$key}; } return 1; } # Called by the lexer once it has done its worst to all the tokens. # Called as a method with the lexer as argument. The return is the # number of parse failures discovered when finalizing. sub __PPIX_LEXER__finalize { my ( $self, $lexer ) = @_; my $rslt = 0; foreach my $elem ( $self->elements() ) { $rslt += $elem->__PPIX_LEXER__finalize( $lexer ); } return $rslt; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( $self, $number ) = @_; foreach my $kid ( $self->children() ) { $number = $kid->__PPIX_LEXER__record_capture_number( $number ); } return $number; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/StringTokenizer.pm000444000765000024 1735413237102475 21370 0ustar00tomstaff000000000000package PPIx::Regexp::StringTokenizer; use 5.006; use strict; use warnings; use base qw{ PPIx::Regexp::Tokenizer }; use Carp; use PPIx::Regexp::Constant qw{ TOKEN_UNKNOWN }; our $VERSION = '0.055'; { # Names of classes containing tokenization machinery. There are few # known ordering requirements, since each class recognizes its own, # and I have tried to prevent overlap. Absent such constraints, the # order is in perceived frequency of acceptance, to keep the search # as short as possible. If I were conscientious I would gather # statistics on this. my @classes = ( # TODO make readonly when acceptable way appears 'PPIx::Regexp::Token::Literal', 'PPIx::Regexp::Token::Interpolation', 'PPIx::Regexp::Token::Control', # Note 1 # 'PPIx::Regexp::Token::CharClass::Simple', # Note 2 # 'PPIx::Regexp::Token::Quantifier', # 'PPIx::Regexp::Token::Greediness', # 'PPIx::Regexp::Token::CharClass::POSIX', # Note 3 # 'PPIx::Regexp::Token::Structure', # 'PPIx::Regexp::Token::Assertion', # 'PPIx::Regexp::Token::Backreference', # 'PPIx::Regexp::Token::Operator', # Note 4 ); # Note 1: If we are in quote mode ( \Q ... \E ), Control makes a # literal out of anything it sees other than \E. So it # needs to come before almost all other tokenizers. Not # Literal, which already makes literals, and not # Interpolation, which is legal in quote mode, but # everything else. # Note 2: CharClass::Simple must come after Literal, because it # relies on Literal to recognize a Unicode named character # ( \N{something} ), so any \N that comes through to it # must be the \N simple character class (which represents # anything but a newline, and was introduced in Perl # 5.11.0. # Note 3: CharClass::POSIX has to come before Structure, since both # look for square brackets, and CharClass::POSIX is the # more particular. # Note 4: Operator relies on Literal making the characters literal # if they appear in a context where they can not be # operators, and Control making them literals if quoting, # so it must come after both. # Return the declared tokenizer classes. sub __tokenizer_classes { return @classes; } } my %bare_delim = map { $_ => 1 } qw{ ' " ` }; sub __PPIX_TOKENIZER__init { my ( $self ) = @_; my @tokens; if ( $self->find_regexp( qr{ \A \s* << }smx ) ) { my ( $leading_white, $next_white, $delim ); if ( $self->find_regexp( qr{ \A ( \s* ) << ( \w+ \n ) }smx ) ) { ( $leading_white, $delim ) = $self->capture(); $next_white = ''; } elsif ( $self->find_regexp( qr{ \A ( \s* ) << ( \s+ ) ( ( ["'] ) .*? \4 \n ) }smx ) ) { ( $leading_white, $next_white, $delim ) = $self->capture(); } else { return $self->__init_error(); } $self->{type} = '<<'; $self->{delimiter_start} = $delim; if ( $delim =~ s/ \A ( ["'] ) ( .* ) \1 \n \z /$2\n/smx ) { my $quote = $1; $delim =~ s/ \\ (?= \Q$quote\E ) //smxg; } '' ne $leading_white and push @tokens, $self->make_token( length $leading_white, 'PPIx::Regexp::Token::Whitespace' ); push @tokens, $self->make_token( length $self->{type}, 'PPIx::Regexp::Token::Structure' ); '' ne $next_white and push @tokens, $self->make_token( length $next_white, 'PPIx::Regexp::Token::Whitespace' ); push @tokens, $self->make_token( length $self->{delimiter_start}, 'PPIx::Regexp::Token::Delimiter' ); my ( $offset ) = $self->find_regexp( qr{ \Q$delim\E }smx ) or return $self->__init_error(); my $cursor_limit = $self->{cursor_curr} + $offset; $self->{trace} and warn "Tokenizer found here doc end delimiter at $cursor_limit\n"; $self->{cursor_limit} = $cursor_limit; $self->{cursor_modifiers} = $cursor_limit + length $delim; $self->{delimiter_finish} = $delim; } elsif ( $self->find_regexp( qr{ \A ( \s* ) ( qq | q | qx )? ( \s* ) ( [^\w\s] ) }smx ) ) { my ( $leading_white, $type, $next_white, $delim ) = $self->capture(); unless ( defined $type ) { $bare_delim{$delim} or return $self->__init_error(); $type = ''; } $self->{type} = $type; '' ne $leading_white and push @tokens, $self->make_token( length $leading_white, 'PPIx::Regexp::Token::Whitespace' ); push @tokens, $self->make_token( length $type, 'PPIx::Regexp::Token::Structure' ); '' ne $next_white and push @tokens, $self->make_token( length $next_white, 'PPIx::Regexp::Token::Whitespace' ); $self->{delimiter_start} = substr $self->{content}, $self->{cursor_curr}, 1; $self->{trace} and warn "Tokenizer found string start delimiter '$self->{delimiter_start}' at $self->{cursor_curr}\n"; my $offset = $self->find_matching_delimiter() or return $self->__init_error( 'Tokenizer found mismatched string delimiters' ); my $cursor_limit = $self->{cursor_curr} + $offset; $self->{trace} and warn "Tokenizer found string end delimiter at $cursor_limit\n"; $self->{cursor_limit} = $cursor_limit; $self->{cursor_modifiers} = $cursor_limit + 1; $self->{delimiter_finish} = substr $self->{content}, $self->{cursor_limit}, 1; push @tokens, $self->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ); } else { return $self->__init_error(); } { pos $self->{content} = $self->{cursor_modifiers}; local $self->{cursor_curr} = $self->{cursor_modifiers}; local $self->{cursor_limit} = length $self->{content}; my @trailing; if ( my $len = $self->find_regexp( qr{ \A \s+ }smx ) ) { push @trailing, $self->make_token( $len, 'PPIx::Regexp::Token::Whitespace' ); } if ( my $len = $self->find_regexp( qr{ \A .+ }smx ) ) { push @trailing, $self->make_token( $len, TOKEN_UNKNOWN, { error => 'Trailing characters after expression', } ); } $self->{trailing_tokens} = \@trailing; $self->{effective_modifiers} = undef; $self->{modifiers} = [ {} ]; } $self->{find} = undef; $self->_set_mode( 'repl' ); return @tokens; } # Return the number of extra delimited parts. This will be 0 for all # strings. sub __number_of_extra_parts { return 0; } # Return the classes for the parts of the expression. sub __part_classes { return ( 'PPIx::Regexp::Structure::Replacement' ); } { my %from_delim = map { $_ => 1 } '', 'qx', '<<'; my %from_type = map { $_ => 1 } qw{ qq qx }; sub interpolates { my ( $self ) = @_; $from_delim{$self->{type}} and return $self->{delimiter_start} !~ m/ \A ' /smx; return $from_type{$self->{type}}; } } 1; __END__ =head1 NAME PPIx::Regexp::StringTokenizer - Tokenize a string literal =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qq{foo$bar}', parse => 'string' ) ->print(); C is a L. C has no descendants. =head1 DESCRIPTION This class provides tokenization of string literals. It is deprecated in favor of the use of L. =head1 METHODS This class supports no public methods over and above those of the superclass. =head1 SEE ALSO L. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Tom Wyant F =head1 COPYRIGHT AND LICENSE Copyright (C) 2015-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure.pm000444000765000024 2556313237102475 20230 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure - Represent a structure. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(foo)}' )->print(); =head1 INHERITANCE C is a L. C is the parent of L, L, L, L, L, L, L, L, L, L, L and L. =head1 DESCRIPTION This class represents a bracketed construction of some sort. The brackets considered part of the structure, but not inside it. So the C method returns the brackets if they are defined, but the C method does not. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Structure; use strict; use warnings; use base qw{ PPIx::Regexp::Node }; use Carp qw{ confess }; use PPIx::Regexp::Constant qw{ STRUCTURE_UNKNOWN }; use PPIx::Regexp::Util qw{ __instance }; use Scalar::Util qw{ refaddr }; our $VERSION = '0.055'; use constant ELEMENT_UNKNOWN => STRUCTURE_UNKNOWN; sub __new { my ( $class, @args ) = @_; my %brkt; if ( ref $args[0] eq 'HASH' ) { %brkt = %{ shift @args }; foreach my $key ( qw{ start type finish } ) { ref $brkt{$key} eq 'ARRAY' or $brkt{$key} = [ $brkt{$key} ]; } } else { $brkt{finish} = [ @args ? pop @args : () ]; $brkt{start} = [ @args ? shift @args : () ]; while ( @args && ! $args[0]->significant() ) { push @{ $brkt{start} }, shift @args; } $brkt{type} = []; if ( __instance( $args[0], 'PPIx::Regexp::Token::GroupType' ) ) { push @{ $brkt{type} }, shift @args; while ( @args && ! $args[0]->significant() ) { push @{ $brkt{type} }, shift @args; } } } $class->_check_for_interpolated_match( \%brkt, \@args ); my $self = $class->SUPER::__new( @args ) or return; if ( __instance( $brkt{type}[0], 'PPIx::Regexp::Token::GroupType' ) ) { ( my $reclass = ref $brkt{type}[0] ) =~ s/ Token::GroupType /Structure/smx; $reclass->can( 'start' ) or confess "Programming error - $reclass not loaded"; bless $self, $reclass; } foreach my $key ( qw{ start type finish } ) { $self->{$key} = []; ref $brkt{$key} eq 'ARRAY' or confess "Programming error - '$brkt{$key}' not an ARRAY"; foreach my $val ( @{ $brkt{$key} } ) { defined $val or next; __instance( $val, 'PPIx::Regexp::Element' ) or confess "Programming error - '$val' not a ", "PPIx::Regexp::Element"; push @{ $self->{$key} }, $val; $val->_parent( $self ); } } @{ $self->{finish} } or $self->{error} = 'Missing end delimiter'; return $self; } sub elements { my ( $self ) = @_; if ( wantarray ) { return ( @{ $self->{start} }, @{ $self->{type} }, @{ $self->{children} }, @{ $self->{finish} }, ); } elsif ( defined wantarray ) { my $size = scalar @{ $self->{start} }; $size += scalar @{ $self->{type} }; $size += scalar @{ $self->{children} }; $size += scalar @{ $self->{finish} }; return $size; } else { return; } } sub explain { my ( $self ) = @_; if ( my $type = $self->type() ) { return $type->explain(); } if ( my $start = $self->start() ) { return $start->explain(); } return $self->__no_explanation(); } =head2 finish my $elem = $struct->finish(); my @elem = $struct->finish(); my $elem = $struct->finish( 0 ); Returns the finishing structure element. This is included in the C but not in the C. The finishing element is actually an array, though it should never have more than one element. Calling C in list context gets you all elements of the array. Calling it in scalar context gets you an element of the array, defaulting to element 0 if no argument is passed. =cut sub finish { my ( $self, $inx ) = @_; wantarray and return @{ $self->{finish} }; return $self->{finish}[ defined $inx ? $inx : 0 ]; } sub first_element { my ( $self ) = @_; $self->{start}[0] and return $self->{start}[0]; $self->{type}[0] and return $self->{type}[0]; if ( my $elem = $self->SUPER::first_element() ) { return $elem; } $self->{finish}[0] and return $self->{finish}[0]; return; } sub last_element { my ( $self ) = @_; $self->{finish}[-1] and return $self->{finish}[-1]; if ( my $elem = $self->SUPER::last_element() ) { return $elem; } $self->{type}[-1] and return $self->{type}[-1]; $self->{start}[-1] and return $self->{start}[-1]; return; } =head2 start my $elem = $struct->start(); my @elem = $struct->start(); my $elem = $struct->start( 0 ); Returns the starting structure element. This is included in the C but not in the C. The starting element is actually an array. The first element (element 0) is the actual starting delimiter. Subsequent elements, if any, are insignificant elements (comments or white space) absorbed into the start element for ease of parsing subsequent elements. Calling C in list context gets you all elements of the array. Calling it in scalar context gets you an element of the array, defaulting to element 0 if no argument is passed. =cut sub start { my ( $self, $inx ) = @_; wantarray and return @{ $self->{start} }; return $self->{start}[ defined $inx ? $inx : 0 ]; } =head2 type my $elem = $struct->type(); my @elem = $struct->type(); my $elem = $struct->type( 0 ); Returns the group type if any. This will be the leading L token if any. This is included in C but not in C. The type is actually an array. The first element (element 0) is the actual type determiner. Subsequent elements, if any, are insignificant elements (comments or white space) absorbed into the type element for consistency with the way the start element is handled. Calling C in list context gets you all elements of the array. Calling it in scalar context gets you an element of the array, defaulting to element 0 if no argument is passed. =cut sub type { my ( $self, $inx ) = @_; wantarray and return @{ $self->{type} }; return $self->{type}[ defined $inx ? $inx : 0 ]; } # Check for things like (?$foo:...) or (?$foo) sub _check_for_interpolated_match { my ( undef, $brkt, $args ) = @_; # Invocant unused # Everything we are interested in begins with a literal '?' followed # by an interpolation. __instance( $args->[0], 'PPIx::Regexp::Token::Unknown' ) and $args->[0]->content() eq '?' and __instance( $args->[1], 'PPIx::Regexp::Token::Interpolation' ) or return; my $hiwater = 2; # Record how far we got into the arguments for # subsequent use detecting things like # (?$foo). # If we have a literal ':' as the third argument: # GroupType::Modifier, rebless the ':' so we know not to match # against it, and splice all three tokens into the type. if ( __instance( $args->[2], 'PPIx::Regexp::Token::Literal' ) && $args->[2]->content() eq ':' ) { # Rebless the '?' as a GroupType::Modifier. PPIx::Regexp::Token::GroupType::Modifier->__PPIX_ELEM__rebless( $args->[0] ); # Rebless the ':' as a GroupType, just so it does not look like # something to match against. PPIx::Regexp::Token::GroupType->__PPIX_ELEM__rebless( $args->[2] ); # Shove our three significant tokens into the type. push @{ $brkt->{type} }, splice @{ $args }, 0, 3; # Stuff all the immediately-following insignificant tokens into # the type as well. while ( @{ $args } && ! $args->[0]->significant() ) { push @{ $brkt->{type} }, shift @{ $args }; } # Return to the caller, since we have done all the damage we # can. return; } # If we have a literal '-' as the third argument, we might have # something like (?$on-$off:$foo). if ( __instance( $args->[2], 'PPIx::Regexp::Token::Literal' ) && $args->[2]->content() eq '-' && __instance( $args->[3], 'PPIx::Regexp::Token::Interpolation' ) ) { $hiwater = 4; if ( __instance( $args->[4], 'PPIx::Regexp::Token::Literal' ) && $args->[4]->content() eq ':' ) { # Rebless the '?' as a GroupType::Modifier. PPIx::Regexp::Token::GroupType::Modifier->__PPIX_ELEM__rebless( $args->[0] ); # Rebless the '-' and ':' as GroupType, just so they do not # look like something to match against. PPIx::Regexp::Token::GroupType->__PPIX_ELEM__rebless( $args->[2] ); PPIx::Regexp::Token::GroupType->__PPIX_ELEM__rebless( $args->[4] ); # Shove our five significant tokens into the type. push @{ $brkt->{type} }, splice @{ $args }, 0, 5; # Stuff all the immediately-following insignificant tokens # into the type as well. while ( @{ $args } && ! $args->[0]->significant() ) { push @{ $brkt->{type} }, shift @{ $args }; } # Return to the caller, since we have done all the damage we # can. return; } } # If the group contains _any_ significant tokens at this point, we # do _not_ have something like (?$foo). foreach my $inx ( $hiwater .. $#$args ) { $args->[$inx]->significant() and return; } # Rebless the '?' as a GroupType::Modifier. PPIx::Regexp::Token::GroupType::Modifier->__PPIX_ELEM__rebless( $args->[0] ); # Shove all the contents of $args into type, using splice to leave # @{ $args } empty after we do this. push @{ $brkt->{type} }, splice @{ $args }; # We have done all the damage we can. return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Support.pm000444000765000024 705513237102475 17660 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Support - Basis for the PPIx::Regexp support classes =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); =head1 INHERITANCE C is not descended from any other class. C is the parent of L, L and L. =head1 DESCRIPTION This abstract class provides methods for the C support classes. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Support; use strict; use warnings; use PPIx::Regexp::Util qw{ __instance }; our $VERSION = '0.055'; =head2 close_bracket This method takes as its argument a character. If this character is an open bracket the corresponding close bracket is returned. Otherwise C is returned. Only the ASCII bracket characters are considered brackets: (), {}, [], and <>. =cut { my %bracket = ( '(' => ')', '{' => '}', '<' => '>', '[' => ']', ); sub close_bracket { my ( undef, $char ) = @_; # Invocant unused defined $char or return; __instance( $char, 'PPIx::Regexp::Element' ) and $char = $char->content(); return $bracket{$char}; } } =head2 decode This method wraps the Encode::decode subroutine. If the object specifies no encoding or encode_available() returns false, this method simply returns its input string. =cut sub decode { my ( $self, $data ) = @_; defined $self->{encoding} or return $data; encode_available() or return $data; return Encode::decode( $self->{encoding}, $data ); } =head2 encode This method wraps the Encode::encode subroutine. If the object specifies no encoding or encode_available() returns false, this method simply returns its input string. =cut sub encode { my ( $self, $data ) = @_; defined $self->{encoding} or return $data; encode_available() or return $data; return Encode::encode( $self->{encoding}, $data ); } =head2 encode_available This method returns true if the Encode module is available, and false otherwise. If it returns true, the Encode module has actually been loaded. =cut { my $encode_available; sub encode_available { defined $encode_available and return $encode_available; return ( $encode_available = eval { require Encode; 1; } ? 1 : 0 ); } } # This method is to be used only by the PPIx-Regexp package. It returns # the first of its arguments which is defined. It will go away when # (or if!) these modules get 'use 5.010;' at the top. sub __defined_or { my ( undef, @args ) = @_; # Invocant unused foreach my $arg ( @args ) { defined $arg and return $arg; } return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token.pm000444000765000024 731713237102475 17265 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token - Base class for PPIx::Regexp tokens. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}' )->print(); =head1 INHERITANCE C is a L. C is the parent of L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L and L. =head1 DESCRIPTION This class represents the base of the class hierarchy for tokens in the L package. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token; use strict; use warnings; use base qw{PPIx::Regexp::Element}; use Carp qw{ confess }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; our $VERSION = '0.055'; use constant TOKENIZER_ARGUMENT_REQUIRED => 0; sub __new { my ( $class, $content, %arg ) = @_; not $class->TOKENIZER_ARGUMENT_REQUIRED() or $arg{tokenizer} or confess 'Programming error - tokenizer not provided'; my $self = { content => $content, }; foreach my $key ( qw{ perl_version_introduced perl_version_removed } ) { defined $arg{$key} and $self->{$key} = $arg{$key}; } bless $self, ref $class || $class; return $self; } sub content { my ( $self ) = @_; return $self->{content}; } sub perl_version_introduced { my ( $self ) = @_; return defined $self->{perl_version_introduced} ? $self->{perl_version_introduced} : MINIMUM_PERL; } sub perl_version_removed { my ( $self ) = @_; return $self->{perl_version_removed}; } sub unescaped_content { my ( $self ) = @_; my $content = $self->content(); $content =~ s/ \\ (?= . ) //smxg; return $content; } sub scontent { my ( $self ) = @_; $self->significant() and return $self->{content}; return; } # Called by the lexer once it has done its worst to all the tokens. # Called as a method with the lexer as argument. The return is the # number of parse failures discovered when finalizing. sub __PPIX_LEXER__finalize { return 0; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Tokenizer.pm000444000765000024 13750713237102475 20224 0ustar00tomstaff000000000000package PPIx::Regexp::Tokenizer; use strict; use warnings; use base qw{ PPIx::Regexp::Support }; use Carp qw{ carp croak confess }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL TOKEN_LITERAL TOKEN_UNKNOWN }; use PPIx::Regexp::Token::Assertion (); use PPIx::Regexp::Token::Backreference (); use PPIx::Regexp::Token::Backtrack (); use PPIx::Regexp::Token::CharClass::POSIX (); use PPIx::Regexp::Token::CharClass::POSIX::Unknown (); use PPIx::Regexp::Token::CharClass::Simple (); use PPIx::Regexp::Token::Code (); use PPIx::Regexp::Token::Comment (); use PPIx::Regexp::Token::Condition (); use PPIx::Regexp::Token::Control (); use PPIx::Regexp::Token::Delimiter (); use PPIx::Regexp::Token::Greediness (); use PPIx::Regexp::Token::GroupType::Assertion (); use PPIx::Regexp::Token::GroupType::BranchReset (); use PPIx::Regexp::Token::GroupType::Code (); use PPIx::Regexp::Token::GroupType::Modifier (); use PPIx::Regexp::Token::GroupType::NamedCapture (); use PPIx::Regexp::Token::GroupType::Script_Run (); use PPIx::Regexp::Token::GroupType::Subexpression (); use PPIx::Regexp::Token::GroupType::Switch (); use PPIx::Regexp::Token::Interpolation (); use PPIx::Regexp::Token::Literal (); use PPIx::Regexp::Token::Modifier (); use PPIx::Regexp::Token::Operator (); use PPIx::Regexp::Token::Quantifier (); use PPIx::Regexp::Token::Recursion (); use PPIx::Regexp::Token::Structure (); use PPIx::Regexp::Token::Unknown (); use PPIx::Regexp::Token::Whitespace (); use PPIx::Regexp::Util qw{ __choose_tokenizer_class __instance }; use Scalar::Util qw{ looks_like_number }; our $VERSION = '0.055'; our $DEFAULT_POSTDEREF; defined $DEFAULT_POSTDEREF or $DEFAULT_POSTDEREF = 1; { # Names of classes containing tokenization machinery. There are few # known ordering requirements, since each class recognizes its own, # and I have tried to prevent overlap. Absent such constraints, the # order is in perceived frequency of acceptance, to keep the search # as short as possible. If I were conscientious I would gather # statistics on this. my @classes = ( # TODO make readonly when acceptable way appears 'PPIx::Regexp::Token::Literal', 'PPIx::Regexp::Token::Interpolation', 'PPIx::Regexp::Token::Control', # Note 1 'PPIx::Regexp::Token::CharClass::Simple', # Note 2 'PPIx::Regexp::Token::Quantifier', 'PPIx::Regexp::Token::Greediness', 'PPIx::Regexp::Token::CharClass::POSIX', # Note 3 'PPIx::Regexp::Token::Structure', 'PPIx::Regexp::Token::Assertion', 'PPIx::Regexp::Token::Backreference', 'PPIx::Regexp::Token::Operator', # Note 4 ); # Note 1: If we are in quote mode ( \Q ... \E ), Control makes a # literal out of anything it sees other than \E. So it # needs to come before almost all other tokenizers. Not # Literal, which already makes literals, and not # Interpolation, which is legal in quote mode, but # everything else. # Note 2: CharClass::Simple must come after Literal, because it # relies on Literal to recognize a Unicode named character # ( \N{something} ), so any \N that comes through to it # must be the \N simple character class (which represents # anything but a newline, and was introduced in Perl # 5.11.0. # Note 3: CharClass::POSIX has to come before Structure, since both # look for square brackets, and CharClass::POSIX is the # more particular. # Note 4: Operator relies on Literal making the characters literal # if they appear in a context where they can not be # operators, and Control making them literals if quoting, # so it must come after both. # Return the declared tokenizer classes. sub __tokenizer_classes { return @classes; } } { my $errstr; sub new { my ( $class, $re, %args ) = @_; ref $class and $class = ref $class; $errstr = undef; exists $args{default_modifiers} and 'ARRAY' ne ref $args{default_modifiers} and do { $errstr = 'default_modifiers must be an array reference'; return; }; my $self = { capture => undef, # Captures from find_regexp. content => undef, # The string we are tokenizing. cookie => {}, # Cookies cursor_curr => 0, # The current position in the string. cursor_limit => undef, # The end of the portion of the # string being tokenized. cursor_orig => undef, # Position of cursor when tokenizer # called. Used by get_token to prevent # recursion. cursor_modifiers => undef, # Position of modifiers. default_modifiers => $args{default_modifiers} || [], delimiter_finish => undef, # Finishing delimiter of regexp. delimiter_start => undef, # Starting delimiter of regexp. encoding => $args{encoding}, # Character encoding. expect => undef, # Extra classes to expect. expect_next => undef, # Extra classes as of next parse cycle failures => 0, # Number of parse failures. find => undef, # String for find_regexp known => {}, # Known tokenizers, by mode. match => undef, # Match from find_regexp. mode => 'init', # Initialize modifiers => [{}], # Modifier hash. pending => [], # Tokens made but not returned. postderef => defined $args{postderef} ? $args{postderef} : $DEFAULT_POSTDEREF, prior => TOKEN_UNKNOWN, # Prior significant token. source => $re, # The object we were initialized with. strict => $args{strict}, # like "use re 'strict';". trace => __PACKAGE__->__defined_or( $args{trace}, $ENV{PPIX_REGEXP_TOKENIZER_TRACE}, 0 ), }; if ( __instance( $re, 'PPI::Element' ) ) { defined( my $tokenizer_class = __choose_tokenizer_class( $re, { parse => 'guess' } ) ) or return __set_errstr( ref $re, 'not supported' ); $class eq $tokenizer_class or return __set_errstr( ref $re, 'not supported by', $class ); # TODO conditionalizstion on PPI class does not really # belong here, but at the moment I have no other idea of # where to put it. $self->{content} = $re->isa( 'PPI::Token::HereDoc' ) ? join( '', $re->content(), "\n", $re->heredoc(), $re->terminator(), "\n" ) : $re->content(); } elsif ( ref $re ) { return __set_errstr( ref $re, 'not supported' ); } else { $self->{content} = $re; } bless $self, $class; $self->{content} = $self->decode( $self->{content} ); $self->{cursor_limit} = length $self->{content}; $self->{trace} and warn "\ntokenizing '$self->{content}'\n"; return $self; } sub __set_errstr { $errstr = join ' ', @_; return; } sub errstr { return $errstr; } } sub capture { my ( $self ) = @_; $self->{capture} or return; defined wantarray or return; return wantarray ? @{ $self->{capture} } : $self->{capture}; } sub content { my ( $self ) = @_; return $self->{content}; } sub cookie { my ( $self, $name, @args ) = @_; defined $name or confess "Programming error - undefined cookie name"; @args or return $self->{cookie}{$name}; my $cookie = shift @args; if ( ref $cookie eq 'CODE' ) { return ( $self->{cookie}{$name} = $cookie ); } elsif ( defined $cookie ) { confess "Programming error - cookie must be CODE ref or undef"; } else { return delete $self->{cookie}{$name}; } } sub default_modifiers { my ( $self ) = @_; return [ @{ $self->{default_modifiers} } ]; } sub __effective_modifiers { my ( $self ) = @_; 'HASH' eq ref $self->{effective_modifiers} or return {}; return { %{ $self->{effective_modifiers} } }; } sub encoding { my ( $self ) = @_; return $self->{encoding}; } sub expect { my ( $self, @args ) = @_; @args or return; $self->{expect_next} = [ map { m/ \A PPIx::Regexp:: /smx ? $_ : 'PPIx::Regexp::' . $_ } @args ]; $self->{expect} = undef; return; } sub failures { my ( $self ) = @_; return $self->{failures}; } sub find_matching_delimiter { my ( $self ) = @_; $self->{cursor_curr} ||= 0; my $start = substr $self->{content}, $self->{cursor_curr}, 1; my $inx = $self->{cursor_curr}; my $finish = ( my $bracketed = $self->close_bracket( $start ) ) || $start; =begin comment $self->{trace} and warn "Find matching delimiter: Start with '$start' at $self->{cursor_curr}, end with '$finish' at or before $self->{cursor_limit}\n"; =end comment =cut my $nest = 0; while ( ++$inx < $self->{cursor_limit} ) { my $char = substr $self->{content}, $inx, 1; =begin comment $self->{trace} and warn " looking at '$char' at $inx, nest level $nest\n"; =end comment =cut if ( $char eq '\\' && $finish ne '\\' ) { ++$inx; } elsif ( $bracketed && $char eq $start ) { ++$nest; } elsif ( $char eq $finish ) { --$nest < 0 and return $inx - $self->{cursor_curr}; } } return; } sub find_regexp { my ( $self, $regexp ) = @_; ref $regexp eq 'Regexp' or confess 'Argument is a ', ( ref $regexp || 'scalar' ), ' not a Regexp'; defined $self->{find} or $self->_remainder(); $self->{find} =~ $regexp or return; my @capture; foreach my $inx ( 0 .. $#+ ) { if ( defined $-[$inx] && defined $+[$inx] ) { push @capture, $self->{capture} = substr $self->{find}, $-[$inx], $+[$inx] - $-[$inx]; } else { push @capture, undef; } } $self->{match} = shift @capture; $self->{capture} = \@capture; # The following circumlocution seems to be needed under Perl 5.13.0 # for reasons I do not fathom -- at least in the case where # wantarray is false. RT 56864 details the symptoms, which I was # never able to reproduce outside Perl::Critic. But returning $+[0] # directly, the value could transmogrify between here and the # calling module. ## my @data = ( $-[0], $+[0] ); ## return wantarray ? @data : $data[1]; return wantarray ? ( $-[0] + 0, $+[0] + 0 ) : $+[0] + 0; } sub get_mode { my ( $self ) = @_; return $self->{mode}; } sub get_start_delimiter { my ( $self ) = @_; return $self->{delimiter_start}; } sub get_token { my ( $self ) = @_; caller eq __PACKAGE__ or $self->{cursor_curr} > $self->{cursor_orig} or confess 'Programming error - get_token() called without ', 'first calling make_token()'; my $handler = '__PPIX_TOKENIZER__' . $self->{mode}; my $code = $self->can( $handler ) or confess 'Programming error - ', "Getting token in mode '$self->{mode}'. ", "cursor_curr = $self->{cursor_curr}; ", "cursor_limit = $self->{cursor_limit}; ", "length( content ) = ", length $self->{content}, "; content = '$self->{content}'"; my $character = substr( $self->{content}, $self->{cursor_curr}, 1 ); $self->{trace} and warn "get_token() got '$character' from $self->{cursor_curr}\n"; return ( $code->( $self, $character ) ); } sub interpolates { my ( $self ) = @_; return $self->{delimiter_start} ne q{'}; } sub make_token { my ( $self, $length, $class, $arg ) = @_; defined $class or $class = caller; if ( $length + $self->{cursor_curr} > $self->{cursor_limit} ) { $length = $self->{cursor_limit} - $self->{cursor_curr} or return; } $class =~ m/ \A PPIx::Regexp:: /smx or $class = 'PPIx::Regexp::' . $class; my $content = substr $self->{content}, $self->{cursor_curr}, $length; $self->{trace} and warn "make_token( $length, '$class' ) => '$content'\n"; $self->{trace} > 1 and warn " make_token: cursor_curr = $self->{cursor_curr}; ", "cursor_limit = $self->{cursor_limit}\n"; my $token = $class->__new( $content, tokenizer => $self, %{ $arg || {} } ) or return; $token->significant() and $self->{expect} = undef; $token->isa( TOKEN_UNKNOWN ) and $self->{failures}++; $self->{cursor_curr} += $length; $self->{find} = undef; $self->{match} = undef; $self->{capture} = undef; foreach my $name ( keys %{ $self->{cookie} } ) { my $cookie = $self->{cookie}{$name}; $cookie->( $self, $token ) or delete $self->{cookie}{$name}; } # Record this token as the prior token if it is significant. We must # do this after processing cookies, so that the cookies have access # to the old token if they want. $token->significant() and $self->{prior_significant_token} = $token; return $token; } sub match { my ( $self ) = @_; return $self->{match}; } sub modifier { my ( $self, $modifier ) = @_; return PPIx::Regexp::Token::Modifier::__asserts( $self->{modifiers}[-1], $modifier ); } sub modifier_duplicate { my ( $self ) = @_; push @{ $self->{modifiers} }, { %{ $self->{modifiers}[-1] } }; return; } sub modifier_modify { my ( $self, %args ) = @_; # Modifier code is centralized in PPIx::Regexp::Token::Modifier $self->{modifiers}[-1] = PPIx::Regexp::Token::Modifier::__PPIX_TOKENIZER__modifier_modify( $self->{modifiers}[-1], \%args ); return; } sub modifier_pop { my ( $self ) = @_; @{ $self->{modifiers} } > 1 and pop @{ $self->{modifiers} }; return; } sub next_token { my ( $self ) = @_; { if ( @{ $self->{pending} } ) { return shift @{ $self->{pending} }; } if ( $self->{cursor_curr} >= $self->{cursor_limit} ) { $self->{cursor_limit} >= length $self->{content} and return; $self->{mode} eq 'finish' and return; $self->_set_mode( 'finish' ); $self->{cursor_limit} += length $self->{delimiter_finish}; } if ( my @tokens = $self->get_token() ) { push @{ $self->{pending} }, @tokens; redo; } } return; } sub peek { my ( $self, $offset ) = @_; defined $offset or $offset = 0; $offset < 0 and return; $offset += $self->{cursor_curr}; $offset >= $self->{cursor_limit} and return; return substr $self->{content}, $offset, 1; } sub ppi_document { my ( $self ) = @_; defined $self->{find} or $self->_remainder(); return PPI::Document->new( \"$self->{find}" ); } sub prior { my ( $self, $method, @args ) = @_; $self->_deprecation_notice( method => 'prior', 'prior_significant_token()' ); defined $method or return $self->{prior_significant_token}; $self->{prior_significant_token}->can( $method ) or confess 'Programming error - ', ( ref $self->{prior_significant_token} || $self->{prior_significant_token} ), ' does not support method ', $method; return $self->{prior_significant_token}->$method( @args ); } sub prior_significant_token { my ( $self, $method, @args ) = @_; defined $method or return $self->{prior_significant_token}; $self->{prior_significant_token}->can( $method ) or confess 'Programming error - ', ( ref $self->{prior_significant_token} || $self->{prior_significant_token} ), ' does not support method ', $method; return $self->{prior_significant_token}->$method( @args ); } # my $length = $token->__recognize_postderef( $tokenizer, $iterator ). # # This method is private to the PPIx-Regexp package, and may be changed # or retracted without warning. What it does is to recognize postfix # dereferences. It returns the length in characters of the first postfix # dereference found, or a false value if none is found. This returns # false immediately unless the tokenizer was instantiated with the # C argument true, or if it was not specified and # C<$DEFAULT_POSTDEREF> was true when the tokenizer was instantiated. # # The optional $iterator argument can be one of the following: # - A code reference, which will be called to provide PPI::Element # objects to be checked to see if they represent a postfix # dereference. # - A PPI::Element, which is checked to see if it is a postfix # dereference. # - Undef, or omitted, in which case ppi() is called on the invocant, # and everything that follows the '->' operator is checked to see if # it is a postfix dereference. # - Anything else results in an exception and stack trace. { # %* &* ** my %magic_var = map { $_ => 1 } qw{ @* $* }; my %magic_oper = map { $_ => 1 } qw{ & ** % }; my %sliceable = map { $_ => 1 } qw{ @ % }; my %post_slice = map { $_ => 1 } qw< { [ >; # ] } sub __recognize_postderef { my ( $self, $token, $iterator ) = @_; $self->{postderef} or return; # Note that if ppi() gets called I have to hold a reference to # the returned object until I am done with all its children. my $ppi; if ( ! defined $iterator ) { $ppi = $token->ppi(); my @ops = grep { '->' eq $_->content() } @{ $ppi->find( 'PPI::Token::Operator' ) || [] }; $iterator = sub { my $op = shift @ops or return; return $op->snext_sibling(); }; } elsif ( $iterator->isa( 'PPI::Element' ) ) { my @eles = ( $iterator ); $iterator = sub { return shift @eles; }; } elsif ( 'CODE' ne ref $iterator ) { confess 'Programming error - Iterator not understood'; } my $accept = $token->__postderef_accept_cast(); while ( my $elem = $iterator->() ) { my $content = $elem->content(); $content =~ m/ \A ( . \#? ) /smx and $accept->{$1} or next; my $length = length $content; # PPI parses '$x->@*' as containing magic variable '@*'. # Similarly for '$*' and '$#*'. I think this is a bug, and # they should be parsed as casts, but ... if ( $elem->isa( 'PPI::Token::Magic' ) ) { $magic_var{$content} and return $length; if ( '$#' eq $content ) { my $next = $elem->snext_sibling() or return $length; '*' eq substr $next->content(), 0, 1 and return $length + 1; } } # PPI parses '%*' as a cast of '%' followed by a splat, but # I think it is likely that if it ever supports postderef # operators that they will be casts. It currently parses # '**' as an operator and '&*' as two operators, but the # logic is pretty much the same as for a cast, so they get # handled here too. if ( $elem->isa( 'PPI::Token::Cast' ) || $elem->isa( 'PPI::Token::Operator' ) && $magic_oper{$content} ) { # Maybe PPI will eventually parse something like '$*' as # a cast, so ... $content =~ m/ [*] \z /smx and return $length; # Or maybe it will parse the asterisk separately, but I # have no idea what its class will be. my $next = $elem->snext_sibling() or return; my $next_content = $next->content(); my $next_char = substr $next_content, 0, 1; '*' eq $next_char and return $length + 1; # We may still have a slice. $sliceable{$content} and $post_slice{$next_char} and return $length + length $next_content; # TODO maybe PPI will do something completely # unanticipated with postderef. } # Otherwise, we're not a postfix dereference; try the next # iteration. } # No postfix dereference found. return; } } sub significant { return 1; } sub strict { my ( $self ) = @_; return $self->{strict}; } sub _known_tokenizers { my ( $self ) = @_; my $mode = $self->{mode}; my @expect; if ( $self->{expect_next} ) { $self->{expect} = $self->{expect_next}; $self->{expect_next} = undef; } if ( $self->{expect} ) { @expect = $self->_known_tokenizer_check( @{ $self->{expect} } ); } exists $self->{known}{$mode} and return ( @expect, @{ $self->{known}{$mode} } ); my @found = $self->_known_tokenizer_check( $self->__tokenizer_classes() ); $self->{known}{$mode} = \@found; return (@expect, @found); } sub _known_tokenizer_check { my ( $self, @args ) = @_; my $handler = '__PPIX_TOKENIZER__' . $self->{mode}; my @found; foreach my $class ( @args ) { $class->can( $handler ) or next; push @found, $class; } return @found; } sub tokens { my ( $self ) = @_; my @rslt; while ( my $token = $self->next_token() ) { push @rslt, $token; } return @rslt; } # $self->_deprecation_notice( $type, $name ); # # This method centralizes deprecation. Type is 'attribute' or # 'method'. Deprecation is driven of the %deprecate hash. Values # are: # false - no warning # 1 - warn on first use # 2 - warn on each use # 3 - die on each use. # # $self->_deprecation_in_progress( $type, $name ) # # This method returns true if the deprecation is in progress. In # fact it returns the deprecation level. { my %deprecate = ( attribute => { }, method => { prior => 3, }, ); sub _deprecation_notice { my ( undef, $type, $name, $repl ) = @_; # Invocant unused $deprecate{$type} or return; $deprecate{$type}{$name} or return; my $msg = sprintf 'The %s %s is %s', $name, $type, $deprecate{$type}{$name} > 2 ? 'removed' : 'deprecated'; defined $repl and $msg .= "; use $repl instead"; $deprecate{$type}{$name} >= 3 and croak $msg; warnings::enabled( 'deprecated' ) and carp $msg; $deprecate{$type}{$name} == 1 and $deprecate{$type}{$name} = 0; return; } =begin comment sub _deprecation_in_progress { my ( $self, $type, $name ) = @_; $deprecate{$type} or return; return $deprecate{$type}{$name}; } =end comment =cut } sub _remainder { my ( $self ) = @_; $self->{cursor_curr} > $self->{cursor_limit} and confess "Programming error - Trying to find past end of string"; $self->{find} = substr( $self->{content}, $self->{cursor_curr}, $self->{cursor_limit} - $self->{cursor_curr} ); return; } sub _make_final_token { my ( $self, $len, $class, $arg ) = @_; my $token = $self->make_token( $len, $class, $arg ); $self->_set_mode( 'kaput' ); return $token; } sub _set_mode { my ( $self, $mode ) = @_; $self->{trace} and warn "Tokenizer going from mode $self->{mode} to $mode\n"; $self->{mode} = $mode; if ( 'kaput' eq $mode ) { $self->{cursor_curr} = $self->{cursor_limit} = length $self->{content}; } return; } sub __init_error { my ( $self , $err ) = @_; defined $err or $err = 'Tokenizer found illegal first characters'; return $self->_make_final_token( length $self->{content}, TOKEN_UNKNOWN, { error => $err, }, ); } sub __PPIX_TOKENIZER__init { my ( $self ) = @_; $self->find_regexp( qr{ \A ( \s* ) ( qr | m | s )? ( \s* ) (?: [^\w\s] ) }smx ) or return $self->__init_error(); my ( $leading_white, $type, $next_white ) = $self->capture(); defined $type or $type = ''; $self->{type} = $type; my @tokens; '' ne $leading_white and push @tokens, $self->make_token( length $leading_white, 'PPIx::Regexp::Token::Whitespace' ); push @tokens, $self->make_token( length $type, 'PPIx::Regexp::Token::Structure' ); '' ne $next_white and push @tokens, $self->make_token( length $next_white, 'PPIx::Regexp::Token::Whitespace' ); $self->{delimiter_start} = substr $self->{content}, $self->{cursor_curr}, 1; $self->{trace} and warn "Tokenizer found regexp start delimiter '$self->{delimiter_start}' at $self->{cursor_curr}\n"; if ( my $offset = $self->find_matching_delimiter() ) { my $cursor_limit = $self->{cursor_curr} + $offset; $self->{trace} and warn "Tokenizer found regexp end delimiter at $cursor_limit\n"; if ( $self->__number_of_extra_parts() ) { ### my $found_embedded_comments; if ( $self->close_bracket( $self->{delimiter_start} ) ) { pos $self->{content} = $self->{cursor_curr} + $offset + 1; # If we're bracketed, there may be Perl comments between # the regex and the replacement. PPI gets the parse # wrong as of 1.220, but if we get the handling of the # underlying string right, we will Just Work when PPI # gets it right. while ( $self->{content} =~ m/ \G \s* \n \s* \# [^\n]* /smxgc ) { ## $found_embedded_comments = 1; } $self->{content} =~ m/ \s* /smxgc; } else { pos $self->{content} = $self->{cursor_curr} + $offset; } # Localizing cursor_curr and delimiter_start would be # cleaner, but I don't want the old values restored if a # parse error occurs. my $cursor_curr = $self->{cursor_curr}; my $delimiter_start = $self->{delimiter_start}; $self->{cursor_curr} = pos $self->{content}; $self->{delimiter_start} = substr $self->{content}, $self->{cursor_curr}, 1; $self->{trace} and warn "Tokenizer found replacement start delimiter '$self->{delimiter_start}' at $self->{cursor_curr}\n"; if ( my $s_off = $self->find_matching_delimiter() ) { $self->{cursor_modifiers} = $self->{cursor_curr} + $s_off + 1; $self->{trace} and warn "Tokenizer found replacement end delimiter at @{[ $self->{cursor_curr} + $s_off ]}\n"; $self->{cursor_curr} = $cursor_curr; $self->{delimiter_start} = $delimiter_start; } else { $self->{trace} and warn 'Tokenizer failed to find replacement', "end delimiter starting at $self->{cursor_curr}\n"; $self->{cursor_curr} = 0; # TODO If I were smart enough here I could check for # PPI mis-parses like s{foo} # #{bar} # {baz} # here, doing so if $found_embedded_comments (commented # out above) is true. The problem is that there seem to # as many mis-parses as there are possible delimiters. return $self->__init_error( 'Tokenizer found mismatched replacement delimiters', ); } } else { $self->{cursor_modifiers} = $cursor_limit + 1; } $self->{cursor_limit} = $cursor_limit; } else { $self->{cursor_curr} = 0; return $self->_make_final_token( length( $self->{content} ), TOKEN_UNKNOWN, { error => 'Tokenizer found mismatched regexp delimiters', }, ); } { my @mods = @{ $self->{default_modifiers} }; pos $self->{content} = $self->{cursor_modifiers}; local $self->{cursor_curr} = $self->{cursor_modifiers}; local $self->{cursor_limit} = length $self->{content}; my @trailing; { my $len = $self->find_regexp( qr{ \A [[:lower:]]* }smx ); push @trailing, $self->make_token( $len, 'PPIx::Regexp::Token::Modifier' ); } if ( my $len = $self->find_regexp( qr{ \A \s+ }smx ) ) { push @trailing, $self->make_token( $len, 'PPIx::Regexp::Token::Whitespace' ); } if ( my $len = $self->find_regexp( qr{ \A .+ }smx ) ) { push @trailing, $self->make_token( $len, TOKEN_UNKNOWN, { error => 'Trailing characters after expression', } ); } $self->{trailing_tokens} = \@trailing; push @mods, $trailing[0]->content(); $self->{effective_modifiers} = PPIx::Regexp::Token::Modifier::__aggregate_modifiers ( @mods ); $self->{modifiers} = [ { %{ $self->{effective_modifiers} } }, ]; } $self->{delimiter_finish} = substr $self->{content}, $self->{cursor_limit}, 1; push @tokens, $self->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ); $self->_set_mode( 'regexp' ); $self->{find} = undef; return @tokens; } # Match the initial part of the regexp including any leading white # space. The initial delimiter is the first thing not consumed, though # we check it for sanity. sub __initial_match { my ( $self ) = @_; $self->find_regexp( qr{ \A ( \s* ) ( qr | m | s )? ( \s* ) (?: [^\w\s] ) }smx ) or return; my ( $leading_white, $type, $next_white ) = $self->capture(); defined $type or $type = ''; $self->{type} = $type; my @tokens; '' ne $leading_white and push @tokens, $self->make_token( length $leading_white, 'PPIx::Regexp::Token::Whitespace' ); push @tokens, $self->make_token( length $type, 'PPIx::Regexp::Token::Structure' ); '' ne $next_white and push @tokens, $self->make_token( length $next_white, 'PPIx::Regexp::Token::Whitespace' ); return @tokens; } { my %extra_parts = ( s => 1, ); # Return the number of extra delimited parts. This will be 0 except # for s///, which will be 1. sub __number_of_extra_parts { my ( $self ) = @_; return $extra_parts{$self->{type}} || 0; } } { my @part_class = qw{ PPIx::Regexp::Structure::Regexp PPIx::Regexp::Structure::Replacement }; # Return the classes for the parts of the expression. sub __part_classes { my ( $self ) = @_; my $max = $self->__number_of_extra_parts(); return @part_class[ 0 .. $max ]; } } sub __PPIX_TOKENIZER__regexp { my ( $self, $character ) = @_; my $mode = $self->{mode}; my $handler = '__PPIX_TOKENIZER__' . $mode; $self->{cursor_orig} = $self->{cursor_curr}; foreach my $class ( $self->_known_tokenizers() ) { my @tokens = grep { $_ } $class->$handler( $self, $character ); $self->{trace} and warn $class, "->$handler( \$self, '$character' )", " => (@tokens)\n"; @tokens and return ( map { ref $_ ? $_ : $self->make_token( $_, $class ) } @tokens ); } # Find a fallback processor for the character. my $fallback = __PACKAGE__->can( '__PPIX_TOKEN_FALLBACK__' . $mode ) || __PACKAGE__->can( '__PPIX_TOKEN_FALLBACK__regexp' ) || confess "Programming error - unable to find fallback for $mode"; return $fallback->( $self, $character ); } *__PPIX_TOKENIZER__repl = \&__PPIX_TOKENIZER__regexp; sub __PPIX_TOKEN_FALLBACK__regexp { my ( $self, $character ) = @_; # As a fallback in regexp mode, any escaped character is a literal. if ( $character eq '\\' && $self->{cursor_limit} - $self->{cursor_curr} > 1 ) { return $self->make_token( 2, TOKEN_LITERAL ); } # Any normal character is unknown. return $self->make_token( 1, TOKEN_UNKNOWN, { error => 'Tokenizer found unexpected literal', }, ); } sub __PPIX_TOKEN_FALLBACK__repl { my ( $self, $character ) = @_; # As a fallback in replacement mode, any escaped character is a literal. if ( $character eq '\\' && defined ( my $next = $self->peek( 1 ) ) ) { if ( $self->interpolates() || $next eq q<'> || $next eq '\\' ) { return $self->make_token( 2, TOKEN_LITERAL ); } return $self->make_token( 1, TOKEN_LITERAL ); } # So is any normal character. return $self->make_token( 1, TOKEN_LITERAL ); } sub __PPIX_TOKENIZER__finish { my ( $self ) = @_; # $character unused $self->{cursor_limit} > length $self->{content} and confess "Programming error - ran off string"; my @tokens = $self->make_token( length $self->{delimiter_finish}, 'PPIx::Regexp::Token::Delimiter' ); if ( $self->{cursor_curr} == $self->{cursor_modifiers} ) { # We are out of string. Add the trailing tokens (created when we # did the initial bracket scan) and close up shop. push @tokens, @{ delete $self->{trailing_tokens} }; $self->_set_mode( 'kaput' ); } else { # Clear the cookies, because we are going around again. $self->{cookie} = {}; # Move the cursor limit to just before the modifiers. $self->{cursor_limit} = $self->{cursor_modifiers} - 1; # If the preceding regular expression was bracketed, we need to # consume possible whitespace and find another delimiter. if ( $self->close_bracket( $self->{delimiter_start} ) ) { my $accept; # If we are bracketed, there can be honest-to-God Perl # comments between the regexp and the replacement, not just # regexp comments. As of version 1.220, PPI does not get # this parse right, but if we can handle this is a string, # then we will Just Work when PPI gets itself straight. while ( $self->find_regexp( qr{ \A ( \s* \n \s* ) ( \# [^\n]* \n ) }smx ) ) { my ( $white_space, $comment ) = $self->capture(); push @tokens, $self->make_token( length $white_space, 'PPIx::Regexp::Token::Whitespace', ), $self->make_token( length $comment, 'PPIx::Regexp::Token::Comment', ); } $accept = $self->find_regexp( qr{ \A \s+ }smx ) and push @tokens, $self->make_token( $accept, 'PPIx::Regexp::Token::Whitespace' ); my $character = $self->peek(); $self->{delimiter_start} = $character; push @tokens, $self->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ); $self->{delimiter_finish} = substr $self->{content}, $self->{cursor_limit} - 1, 1; } if ( $self->modifier( 'e*' ) ) { # With /e or /ee, the replacement portion is code. We make # it all into one big PPIx::Regexp::Token::Code, slap on the # trailing delimiter and modifiers, and return it all. push @tokens, $self->make_token( $self->{cursor_limit} - $self->{cursor_curr}, 'PPIx::Regexp::Token::Code', { perl_version_introduced => MINIMUM_PERL }, ); $self->{cursor_limit} = length $self->{content}; push @tokens, $self->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ), @{ delete $self->{trailing_tokens} }; $self->_set_mode( 'kaput' ); } else { # Put our mode to replacement. $self->_set_mode( 'repl' ); } } return @tokens; } 1; __END__ =head1 NAME PPIx::Regexp::Tokenizer - Tokenize a regular expression =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class provides tokenization of the regular expression. =head1 METHODS This class provides the following public methods. Methods not documented here (or documented below under L) are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =head2 new my $tokenizer = PPIx::Regexp::Tokenizer->new( 'xyzzy' ); This static method instantiates the tokenizer. You must pass it the regular expression to be parsed, either as a string or as a L of some sort. You can also pass optional name/value pairs of arguments. The option names are specified B a leading dash. Supported options are: =over =item default_modifiers array_reference This argument specifies default statement modifiers. It is optional, but if specified must be an array reference. See the L L documentation for the details. =item encoding name This option specifies the encoding of the string to be tokenized. If specified, an C is done on the string (or the C of the PPI class) before it is tokenized. =item postderef boolean This option specifies whether the tokenizer recognizes postfix dereferencing. See the L L documentation for the details. C<$PPIx::Regexp::Tokenizer::DEFAULT_POSTDEREF> is not exported. =item strict boolean This option specifies whether tokenization should assume C is in effect. The C<'strict'> pragma was introduced in Perl 5.22, and its documentation says that it is experimental, and that there is no commitment to backward compatibility. The same applies to the tokenization produced when this option is asserted. =item trace number Specifying a positive value for this option causes a trace of the tokenization. This option is unsupported in the sense that the author reserves the right to alter it without notice. If this option is unspecified, the value comes from environment variable C (see L). If this environment variable does not exist, the default is 0. =back Undocumented options are unsupported. The returned value is the instantiated tokenizer, or C if instantiation failed. In the latter case a call to L will return the reason. =head2 content print $tokenizer->content(); This method returns the string being tokenized. This will be the result of the L<< PPI::Element->content()|PPI::Element/content >> method if the object was instantiated with a L. =head2 default_modifiers print join ', ', @{ $tokenizer->default_modifiers() }; This method returns a reference to a copy of the array passed to the C argument to L. If this argument was not used to instantiate the object, the return is a reference to an empty array. =head2 encoding This method returns the encoding of the data being parsed, if one was set when the class was instantiated; otherwise it simply returns undef. =head2 errstr my $tokenizer = PPIx::Regexp::Tokenizer->new( 'xyzzy' ) or die PPIx::Regexp::Tokenizer->errstr(); This static method returns an error description if tokenizer instantiation failed. =head2 failures print $tokenizer->failures(), " tokenization failures\n"; This method returns the number of tokenization failures encountered. A tokenization failure is represented in the output token stream by a L. =head2 modifier $tokenizer->modifier( 'x' ) and print "Tokenizing an extended regular expression\n"; This method returns true if the given modifier character was found on the end of the regular expression, and false otherwise. Starting with version 0.036_01, if the argument is a single-character modifier followed by an asterisk (intended as a wild card character), the return is the number of times that modifier appears. In this case an exception will be thrown if you specify a multi-character modifier (e.g. C<'ee*'>), or if you specify one of the match semantics modifiers (e.g. C<'a*'>). =head2 next_token my $token = $tokenizer->next_token(); This method returns the next token in the token stream, or nothing if there are no more tokens. =head2 significant This method exists simply for the convenience of L. It always returns true. =head2 tokens my @tokens = $tokenizer->tokens(); This method returns all remaining tokens in the token stream. =head1 EXTERNAL TOKENIZERS This class does very little of its own tokenization. Instead the token classes contain external tokenization routines, whose name is '__PPIX_TOKENIZER__' concatenated with the current mode of the tokenizer ('regexp' for regular expressions, 'repl' for the replacement string). These external tokenizers are called as static methods, and passed the C object and the current character in the character stream. If the external tokenizer wants to make one or more tokens, it returns an array containing either length in characters for tokens of the tokenizer's own class, or the results of one or more L calls for tokens of an arbitrary class. If the external tokenizer is not interested in the characters starting at the current position it simply returns. The following methods are for the use of external tokenizers, and B =head2 capture if ( $tokenizer->find_regexp( qr{ \A ( foo ) }smx ) ) { foreach ( $tokenizer->capture() ) { print "$_\n"; } } This method returns all the contents of any capture buffers from the previous call to L. The first element of the array (i.e. element 0) corresponds to C<$1>, and so on. The captures are cleared by L, as well as by another call to L. =head2 cookie $tokenizer->cookie( foo => sub { 1 } ); my $cookie = $tokenizer->cookie( 'foo' ); my $old_hint = $tokenizer->cookie( foo => undef ); This method either creates, deletes, or accesses a cookie. A cookie is a code reference which is called whenever the tokenizer makes a token. If it returns a false value, it is deleted. Explicitly setting the cookie to C also deletes it. When you call C<< $tokenizer->cookie( 'foo' ) >>, the current cookie is returned. If you pass a new value of C to delete the token, the deleted cookie (if any) is returned. When the L method calls a cookie, it passes it the tokenizer and the token just made. If a token calls a cookie, it is recommended that it merely pass the tokenizer, though of course the token can do whatever it wants. The cookie mechanism seems to be a bit of a crock, but it appeared to be more work to fix things up in the lexer after the tokenizer got something wrong. The recommended way to write a cookie is to use a closure to store any necessary data, and have a call to the cookie return the data; otherwise the ultimate consumer of the cookie has no way to access the data. Of course, it may be that the presence of the cookie at a certain point in the parse is all that is required. =head2 expect $tokenizer->expect( 'PPIx::Regexp::Token::Code' ); This method inserts a given class at the head of the token scan, for the next iteration only. More than one class can be specified. Class names can be abbreviated by removing the leading 'PPIx::Regexp::'. If no class is specified, this method does nothing. The expectation lasts from the next time L is called until the next time L makes a significant token, or until the next C call if that is done sooner. =head2 find_regexp my $end = $tokenizer->find_regexp( qr{ \A \w+ }smx ); my ( $begin, $end ) = $tokenizer->find_regexp( qr{ \A \w+ }smx ); This method finds the given regular expression in the content, starting at the current position. If called in scalar context, the offset from the current position to the end of the matched string is returned. If called in list context, the offsets to both the beginning and the end of the matched string are returned. =head2 find_matching_delimiter my $offset = $tokenizer->find_matching_delimiter(); This method is used by tokenizers to find the delimiter matching the character at the current position in the content string. If the delimiter is an opening bracket of some sort, bracket nesting will be taken into account. When searching for the matching delimiter, the back slash character is considered to escape the following character, so back-slashed delimiters will be ignored. No other quoting mechanisms are recognized, though, so delimiters inside quotes still count. This is actually the way Perl works, as $ perl -e 'qr<(?{ print "}" })>' demonstrates. This method returns the offset from the current position in the content string to the matching delimiter (which will always be positive), or undef if no match can be found. =head2 get_mode This method returns the name of the current mode of the tokenizer. =head2 get_start_delimiter my $start_delimiter = $tokenizer->get_start_delimiter(); This method is used by tokenizers to access the start delimiter for the regular expression. =head2 get_token my $token = $tokenizer->make_token( 3 ); my @tokens = $tokenizer->get_token(); This method returns the next token that can be made from the input stream. It is B part of the external interface, but is intended for the use of an external tokenizer which calls it after making and retaining its own token to look at the next token ( if any ) in the input stream. If any external tokenizer calls get_token without first calling make_token, a fatal error occurs; this is better than the infinite recursion which would occur if the condition were not trapped. An external tokenizer B return anything returned by get_token; otherwise tokens get lost. =head2 interpolates This method returns true if the top-level structure being tokenized interpolates; that is, if the delimiter is not a single quote. =head2 make_token return $tokenizer->make_token( 3, 'PPIx::Regexp::Token::Unknown' ); This method is used by this class (and possibly by individual tokenizers) to manufacture a token. Its arguments are the number of characters to include in the token, and optionally the class of the token. If no class name is given, the caller's class is used. Class names may be shortened by removing the initial 'PPIx::Regexp::', which will be restored by this method. The token will be manufactured from the given number of characters starting at the current cursor position, which will be adjusted. If the given length would include characters past the end of the string being tokenized, the length is reduced appropriately. If this means a token with no characters, nothing is returned. =head2 match if ( $tokenizer->find_regexp( qr{ \A \w+ }smx ) ) { print $tokenizer->match(), "\n"; } This method returns the string matched by the previous call to L. The match is set to C by L, as well as by another call to L. =head2 modifier_duplicate $tokenizer->modifier_duplicate(); This method duplicates the modifiers on the top of the modifier stack, with the intent of creating a locally-scoped copy of the modifiers. This should only be called by an external tokenizer that is actually creating a modifier scope. In other words, only when creating a L token whose content is '('. =head2 modifier_modify $tokenizer->modifier_modify( name => $value ... ); This method sets new values for the modifiers in the local scope. Only the modifiers whose names are actually passed have their values changed. This method is intended to be called after manufacturing a L token, and passed the results of its C method. =head2 modifier_pop $tokenizer->modifier_pop(); This method removes the modifiers on the top of the modifier stack. This should only be called by an external tokenizer that is ending a modifier scope. In other words, only when creating a L token whose content is ')'. Note that this method will never pop the last modifier item off the stack, to guard against unmatched right parentheses. =head2 peek my $character = $tokenizer->peek(); my $next_char = $tokenizer->peek( 1 ); This method returns the character at the given non-negative offset from the current position. If no offset is given, an offset of 0 is used. If you ask for a negative offset or an offset off the end of the sting, C is returned. =head2 ppi_document This method makes a PPI document out of the remainder of the string, and returns it. =head2 prior $tokenizer->prior( 'can_be_quantified' ) and print "The prior token can be quantified.\n"; This method is deprecated in favor of L. As of version [%% next_version %%] it is a fatal error to call it. Six months after the release of this version it will be removed. I am not sure I need to put this though a deprecation cycle, given that this method is documented as not being part of the public interface, but I choose to err on the side of caution. This method calls the named method on the most-recently-instantiated significant token, and returns the result. Any arguments subsequent to the method name will be passed to the method. Because this method is designed to be used within the tokenizing system, it will die horribly if the named method does not exist. If called with no arguments at all the most-recently-instantiated significant token is returned. =head2 prior_significant_token $tokenizer->prior_significant_token( 'can_be_quantified' ) and print "The prior token can be quantified.\n"; This method calls the named method on the most-recently-instantiated significant token, and returns the result. Any arguments subsequent to the method name will be passed to the method. Because this method is designed to be used within the tokenizing system, it will die horribly if the named method does not exist. If called with no arguments at all the most-recently-instantiated significant token is returned. =head2 strict say 'Parse is ', $tokenizer->strict() ? 'strict' : 'lenient'; This method simply returns true or false, depending on whether the C<'strict'> option to C was true or false. =head1 ENVIRONMENT VARIABLES A tokenizer trace can be requested by setting environment variable PPIX_REGEXP_TOKENIZER_TRACE to a numeric value other than 0. Use of this environment variable is unsupported in the same sense that the C option of L is unsupported. Explicitly specifying the C option to L overrides the environment variable. The real reason this is documented is to give the user a way to troubleshoot funny output from the tokenizer. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Util.pm000444000765000024 764513237102475 17126 0ustar00tomstaff000000000000package PPIx::Regexp::Util; use 5.006; use strict; use warnings; use Carp; use Scalar::Util qw{ blessed }; use base qw{ Exporter }; our @EXPORT_OK = qw{ __choose_tokenizer_class __instance __to_ordinal_en }; our $VERSION = '0.055'; { my @ppi_zoo = ( [ 'PPI::Token::Regexp::Transliterate' ], [ 'PPI::Token::Regexp', 'PPIx::Regexp::Tokenizer' ], [ 'PPI::Token::QuoteLike::Regexp', 'PPIx::Regexp::Tokenizer' ], [ 'PPI::Token::Quote', 'PPIx::Regexp::StringTokenizer' ], [ 'PPI::Token::QuoteLike::Command', 'PPIx::Regexp::StringTokenizer' ], [ 'PPI::Token::QuoteLike::BackTick', 'PPIx::Regexp::StringTokenizer' ], [ 'PPI::Token::HereDoc', 'PPIx::Regexp::StringTokenizer' ], ); my %parse_type = ( guess => sub { my ( $content ) = @_; if ( __instance( $content, 'PPI::Element' ) ) { foreach ( @ppi_zoo ) { $content->isa( $_->[0] ) and return $_->[1]; } return; } elsif ( ref $content ) { return; } else { return $content =~ m/ \A \s* (?: ["'`] | << | (?: (?: qq | q | qx ) \b ) ) /smx ? 'PPIx::Regexp::StringTokenizer' : 'PPIx::Regexp::Tokenizer'; } }, regex => sub { return 'PPIx::Regexp::Tokenizer'; }, string => sub { return 'PPIx::Regexp::StringTokenizer'; }, ); sub __choose_tokenizer_class { my ( $content, $arg ) = @_; my $parse = defined $arg->{parse} ? $arg->{parse} : 'regex'; my $code = $parse_type{$parse} or return PPIx::Regexp::Tokenizer->__set_errstr( "Unknown parse type '$parse'" ); return $code->( $content ); } } sub __instance { my ( $object, $class ) = @_; blessed( $object ) or return; return $object->isa( $class ); } sub __to_ordinal_en { my ( $num ) = @_; $num += 0; 1 == $num % 10 and return "${num}st"; 2 == $num % 10 and return "${num}nd"; 3 == $num % 10 and return "${num}rd"; return "${num}th"; } 1; __END__ =head1 NAME PPIx::Regexp::Util - Utility functions for PPIx::Regexp; =head1 SYNOPSIS use PPIx::Regexp::Util qw{ __instance }; . . . __instance( $foo, 'Bar' ) or die '$foo is not a Bar'; =head1 DESCRIPTION This module contains utility functions for L which it is convenient to centralize. The contents of this module are B to the L package. This documentation is provided for the author's convenience only. Anything in this module is subject to change without notice. I This module exports nothing by default. =head1 SUBROUTINES This module can export the following subroutines: =head2 __instance __instance( $foo, 'Bar' ) and print '$foo isa Bar', "\n"; This subroutine returns true if its first argument is an instance of the class specified by its second argument. Unlike C, the result is always false unless the first argument is a reference. =head2 __to_ordinal_en This subroutine takes as its argument an integer and returns a string representing its ordinal in English. For example say __to_ordinal_en( 17 ); # 17th =cut =head1 SEE ALSO L, which I recommend, but in the case of C I did not want to introduce a dependency on an XS module when all I really wanted was the function of that module's C<_INSTANCE()> subroutine. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2010-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Node000755000765000024 013237102475 16367 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp/Node/Range.pm000444000765000024 630213237102475 20117 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Node::Range - Represent a character range in a character class =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{[a-z]}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a character range in a character class. It is a node rather than a structure because there are no delimiters. The content is simply the two literals with the '-' operator between them. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Node::Range; use strict; use warnings; use base qw{ PPIx::Regexp::Node }; use PPIx::Regexp::Constant qw{ MSG_PROHIBITED_BY_STRICT }; our $VERSION = '0.055'; sub explain { my ( $self ) = @_; my $first = $self->schild( 0 ) or return $self->__no_explanation(); my $last = $self->schild( -1 ) or return $self->__no_explanation(); return sprintf q, $first->content(), $last->content(); } sub __PPIX_LEXER__finalize { my ( $self, $lexer ) = @_; my $rslt = $self->SUPER::__PPIX_LEXER__finalize( $lexer ); if ( $lexer->strict() ) { # If strict is in effect, we're an error unless both ends of the # range are portable. my @kids = $self->schildren(); delete $self->{_range_start}; # Context for compatibility. foreach my $inx ( 0, -1 ) { my $kid = $kids[$inx]; # If we're not a literal, we can not make the test, so we # blindly accept it. $kid->isa( 'PPIx::Regexp::Token::Literal' ) or next; my $content = $kid->content(); $content =~ m/ \A (?: [[:alnum:]] | \\N\{ .* \} ) \z /smx and $self->_range_ends_compatible( $content ) or return $self->_prohibited_by_strict( $rslt ); } } return $rslt; } sub _prohibited_by_strict { my ( $self, $rslt ) = @_; delete $self->{_range_start}; $rslt += $self->__error( join( ' ', 'Non-portable range ends', MSG_PROHIBITED_BY_STRICT ), perl_version_introduced => '5.023008', ); return $rslt; } sub _range_ends_compatible { my ( $self, $content ) = @_; if ( defined( my $start = $self->{_range_start} ) ) { foreach my $re ( qr{ \A [[:upper:]] \z }smx, qr{ \A [[:lower:]] \z }smx, qr{ \A [0-9] \z }smx, qr{ \A \\N \{ .* \} }smx, ) { $start =~ $re or next; return $content =~ $re; } return; } else { $self->{_range_start} = $content; return 1; } } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Node/Unknown.pm000444000765000024 275613237102475 20533 0ustar00tomstaff000000000000package PPIx::Regexp::Node::Unknown; use 5.006; use strict; use warnings; use base qw{ PPIx::Regexp::Node }; our $VERSION = '0.055'; 1; __END__ =head1 NAME PPIx::Regexp::Node::Unknown - Represent an unknown node. =head1 SYNOPSIS None. Sorry. This class was added to support the C option, which was itself an attempt to capture the functionality of C. It is not known to have any other use, and it cannot be instantiated in any straightforward manner. =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class is used for a node which the lexer recognizes as being improperly constructed. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2016-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure000755000765000024 013237102475 17502 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Assertion.pm000444000765000024 322213237102475 22143 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Assertion - Represent a parenthesized assertion =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?<=foo)bar}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents one of the parenthesized assertions, either look ahead or look behind, and either positive or negative. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Assertion; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; use PPIx::Regexp::Constant qw{ LITERAL_LEFT_CURLY_ALLOWED }; # An un-escaped literal left curly bracket can always follow this # element. sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_ALLOWED; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/BranchReset.pm000444000765000024 404313237102475 22376 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::BranchReset - Represent a branch reset group =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?|(foo)|(bar))}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a branch reset group. That is, the construction C<(?|(...)|(...)|...)>. This is new with Perl 5.010. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::BranchReset; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; use Carp qw{ confess }; our $VERSION = '0.055'; # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( $self, $number ) = @_; defined $number or confess 'Programming error - initial $number is undef'; my $original = $number; my $hiwater = $number; foreach my $kid ( $self->children() ) { if ( $kid->isa( 'PPIx::Regexp::Token::Operator' ) && $kid->content() eq '|' ) { $number > $hiwater and $hiwater = $number; $number = $original; } else { $number = $kid->__PPIX_LEXER__record_capture_number( $number ); } } return $number > $hiwater ? $number : $hiwater; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Capture.pm000444000765000024 435613237102475 21610 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Capture - Represent capture parentheses. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(foo)}smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L. =head1 DESCRIPTION This class represents capture parentheses. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Structure::Capture; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; sub explain { my ( $self ) = @_; return sprintf q, $self->number(); } =head2 name my $name = $element->name(); This method returns the name of the capture buffer. Unless the buffer is actually named, this will be C. =cut sub name { return; } =head2 number my $number = $element->number() This method returns the number of the capture buffer. Note that named buffers have numbers also. =cut sub number { my ( $self ) = @_; return $self->{number}; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( $self, $number ) = @_; $self->{number} = $number++; return $self->SUPER::__PPIX_LEXER__record_capture_number( $number ); } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/CharClass.pm000444000765000024 507513237102475 22047 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::CharClass - Represent a character class =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{[fo]}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a square-bracketed character class. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Structure::CharClass; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; use PPIx::Regexp::Constant qw{ LITERAL_LEFT_CURLY_REMOVED_PHASE_2 }; use PPIx::Regexp::Util qw{ __instance }; our $VERSION = '0.055'; sub __new { my ( $class, @args ) = @_; ref $class and $class = ref $class; my %brkt; $brkt{finish} = pop @args; $brkt{start} = shift @args; __instance( $args[0], 'PPIx::Regexp::Token::Operator' ) and $args[0]->content() eq '^' and $brkt{type} = shift @args; return $class->SUPER::__new( \%brkt, @args ); } sub explain { my ( $self ) = @_; $self->negated() and return 'Inverted character class'; return 'Character class'; } =head2 negated $class->negated() and print "Class is negated\n"; This method returns true if the character class is negated -- that is, if the first token inside the left square bracket is a caret (C<^>). =cut sub negated { my ( $self ) = @_; return $self->type() ? 1 : 0; } sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_REMOVED_PHASE_2; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( undef, $number ) = @_; # Invocant unused return $number; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Code.pm000444000765000024 372713237102475 21060 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Code - Represent one of the code structures. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?{print "hello sailor\n")}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents one of the code structures, either (?{ code }) or (??{ code }) =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Code; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; # The only child of this structure should be a single # PPIx::Regexp::Token::Code. Anything else gets turned into the # appropriate ::Unknown object. sub __PPIX_LEXER__finalize { my ( $self ) = @_; # $lexer unused my $count; my $errors = 0; foreach my $kid ( $self->children() ) { if ( $kid->isa( 'PPIx::Regexp::Token::Code' ) ) { $count++ or next; $errors++; $kid->__error( 'Code structure can contain only one code token' ); } else { $errors++; $kid->__error( 'Code structure may not contain a ' . ref $kid ); } } return $errors; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Main.pm000444000765000024 533113237102475 21063 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Main - Represent a regular expression proper, or a substitution =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L and L. =head1 DESCRIPTION This abstract class represents one of the top-level structures in the expression. Both L and L are derived from it. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Structure::Main; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; =head2 delimiters This method returns a string representing the delimiters of a regular expression or substitution string. In the case of something like C, it will return '//' for both the regular expression and the replacement. =cut sub delimiters { my ( $self ) = @_; my @delims; foreach my $method ( qw{ start finish } ) { push @delims, undef; defined ( my $obj = $self->$method() ) or next; defined ( my $str = $obj->content() ) or next; $delims[-1] = $str; } defined ( $delims[0] ) or $delims[0] = $delims[1]; return $delims[0] . $delims[1]; } =head2 interpolates This method returns true if the regular expression or replacement interpolates, and false otherwise. All it really does is to check whether the ending delimiter is a single quote. =cut sub interpolates { my ( $self ) = @_; my $finish = $self->finish( 0 ) or return 1; return q<'> ne $finish->content(); } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Modifier.pm000444000765000024 400413237102475 21731 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Modifier - Represent modifying parentheses =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?i:foo)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents parentheses that apply modifiers to their contents -- even if there are no modifiers. The latter is to say that C<(?:foo)> also ends up as this class. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Modifier; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; # This is a kluge for both determining whether the object asserts # modifiers (hence the 'ductype') and determining whether the given # modifier is actually asserted. The signature is the invocant and the # modifier name, which must not be undef. The return is a boolean. sub __ducktype_modifier_asserted { my ( $self, $modifier ) = @_; foreach my $type ( reverse $self->type() ) { $type->can( '__ducktype_modifier_asserted' ) or next; defined( my $val = $type->__ducktype_modifier_asserted( $modifier ) ) or next; return $val; } return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/NamedCapture.pm000444000765000024 373713237102475 22557 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::NamedCapture - Represent a named capture =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?foo)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a named capture. Its content will be something like one of the following: (? ... ) (?'NAME' ... ) (?P ... ) =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Structure::NamedCapture; use strict; use warnings; use Carp; use base qw{ PPIx::Regexp::Structure::Capture }; our $VERSION = '0.055'; sub explain { my ( $self ) = @_; return sprintf q, $self->name(), $self->number(); } =head2 name my $name = $element->name(); This method returns the name of the capture. =cut sub name { my ( $self ) = @_; my $type = $self->type() or croak 'Programming error - ', __PACKAGE__, ' without type object'; return $type->name(); } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Quantifier.pm000444000765000024 443213237102475 22307 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Quantifier - Represent curly bracket quantifiers =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{fo{2,}}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents curly bracket quantifiers such as C<{3}>, C<{3,}> and C<{3,5}>. The contents are left as literals or interpolations. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Quantifier; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; use PPIx::Regexp::Constant qw{ LITERAL_LEFT_CURLY_ALLOWED }; our $VERSION = '0.055'; sub can_be_quantified { return; } sub explain { my ( $self ) = @_; my $content = $self->content(); if ( $content =~ m/ \A [{] ( .*? ) [}] \z /smx ) { my $quant = $1; my ( $lo, $hi ) = split qr{ , }smx, $quant; defined $hi and '' ne $hi and return "match $lo to $hi times"; $quant =~ m/ , \z /smx and return "match $lo or more times"; $lo =~ m/ [^0-9] /smx and return "match $lo times"; return "match exactly $lo times"; } return $self->SUPER::explain(); } sub is_quantifier { return 1; } sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_ALLOWED; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( undef, $number ) = @_; # Invocant unused return $number; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/RegexSet.pm000444000765000024 467013237102475 21732 0ustar00tomstaff000000000000package PPIx::Regexp::Structure::RegexSet; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; use PPIx::Regexp::Constant qw{ LITERAL_LEFT_CURLY_REMOVED_PHASE_2 }; our $VERSION = '0.055'; sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_REMOVED_PHASE_2; } 1; __END__ =head1 NAME PPIx::Regexp::Structure::RegexSet - Represent a regexp character set =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?[ \w - [fox] ])}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 RESTRICTION When running under Perl 5.6, the extended white space characters are not recognized as white space. =begin comment See the code in PPIx::Regexp::Token::Literal that generates $regex_set_space for the actual machinery. The reason for the restriction is that I was, for some reason, not able to get '\x{...}' to work. =end comment =head1 DESCRIPTION This class represents a regex character set. These were introduced in Perl 5.17.8, and documented as experimental and subject to change. If changes introduced in Perl result in changes in the way C parses the regular expression, C will track the change, even if they are incompatible with the previous parse. If this functionality is retracted and the syntax used for something else, C will forget completely about regex character sets. At some point, the documentation started calling these "Extended Bracketed Character Classes", and documenting them in L. =head1 METHODS This class supports no public methods over and above those supported by the superclasses. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2013-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Regexp.pm000444000765000024 572113237102475 21434 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Regexp - Represent the top-level regular expression =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents the top-level regular expression. In the example given in the L, the C<{foo}> will be represented by this class. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Structure::Regexp; use strict; use warnings; use base qw{ PPIx::Regexp::Structure::Main }; our $VERSION = '0.055'; sub can_be_quantified { return; } =head2 capture_names foreach my $name ( $re->capture_names() ) { print "Capture name '$name'\n"; } This method returns the capture names found in the regular expression. =cut sub capture_names { my ( $self ) = @_; my %name; my $captures = $self->find( 'PPIx::Regexp::Structure::NamedCapture') or return; foreach my $grab ( @{ $captures } ) { $name{$grab->name()}++; } return ( sort keys %name ); } sub explain { return 'Regular expression'; } =head2 max_capture_number print "Highest used capture number ", $re->max_capture_number(), "\n"; This method returns the highest capture number used by the regular expression. If there are no captures, the return will be 0. =cut sub max_capture_number { my ( $self ) = @_; return $self->{max_capture_number}; } # Called by the lexer once it has done its worst to all the tokens. # Called as a method with the lexer as argument. The return is the # number of parse failures discovered when finalizing. sub __PPIX_LEXER__finalize { my ( $self, $lexer ) = @_; my $rslt = 0; foreach my $elem ( $self->elements() ) { $rslt += $elem->__PPIX_LEXER__finalize( $lexer ); } # Calculate the maximum capture group, and number all the other # capture groups along the way. $self->{max_capture_number} = $self->__PPIX_LEXER__record_capture_number( 1 ) - 1; return $rslt; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Replacement.pm000444000765000024 326713237102475 22444 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Replacement - Represent the replacement in s/// =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 's{foo}{bar}smxg' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents the replacement in a substitution operation. In the example given in the L, the C<{bar}> will be represented by this class. Note that if the substitution is not bracketed (e.g. C), this structure will contain no starting delimiter. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Replacement; use strict; use warnings; use base qw{ PPIx::Regexp::Structure::Main }; our $VERSION = '0.055'; sub can_be_quantified { return; } sub explain { return 'Replacement string or expression'; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Script_Run.pm000444000765000024 306313237102475 22267 0ustar00tomstaff000000000000# Cargo cult to try to prevent CPAN from indexing package PPIx::Regexp::Structure::Script_Run; use 5.006; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; use Carp; our $VERSION = '0.055'; 1; __END__ =head1 NAME PPIx::Regexp::Structure::Script_Run - Represent a script run group =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(+script_run:\d)}' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a script run group. That is, the construction C<(+script_run:...)>. This is new with Perl 5.27.8. If this construction does not make it into Perl 5.28, this class will be retracted. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Subexpression.pm000444000765000024 265013237102475 23051 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Subexpression - Represent an independent subexpression =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo(?>bar)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents an independent subexpression which must (says F) match at the current location. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Subexpression; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Switch.pm000444000765000024 560113237102475 21440 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Switch - Represent a switch =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?(1)foo|bar)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a switch, or conditional expression. The condition will be the first child. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Switch; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; sub __PPIX_LEXER__finalize { my ( $self, $lexer ) = @_; # Assume no errors. my $rslt = 0; # Number of allowed alternations not known yet. my $alternations; # If we are a valid switch, the first child is the condition. Make # sure we have a first child and that it is of the expected class. # If it is, determine how many alternations are allowed. if ( my $condition = $self->child( 0 ) ) { foreach my $class ( qw{ PPIx::Regexp::Structure::Assertion PPIx::Regexp::Structure::Code PPIx::Regexp::Token::Condition } ) { $condition->isa( $class ) or next; $alternations = $condition->content() eq '(DEFINE)' ? 0 : 1; last; } } if ( defined $alternations ) { # If we figured out how many alternations were allowed, count # them, changing surplus ones to the unknown token. foreach my $kid ( $self->children () ) { $kid->isa( 'PPIx::Regexp::Token::Operator' ) or next; $kid->content() eq '|' or next; --$alternations >= 0 and next; $kid->__error( 'Too many alternatives for switch' ); } } else { # If we could not figure out how many alternations were allowed, # it means we did not understand our condition. Rebless # ourselves to the unknown structure and count a parse failure. $self->__error( 'Switch condition not understood' ); $rslt++; } # Delegate to the superclass to finalize our children, now that we # have finished messing with them. $rslt += $self->SUPER::__PPIX_LEXER__finalize( $lexer ); return $rslt; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Structure/Unknown.pm000444000765000024 260613237102475 21640 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Structure::Unknown - Represent an unknown structure. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?(foo)bar|baz|burfle)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class is used for a structure which the lexer recognizes as being improperly constructed. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Structure::Unknown; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.055'; 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token000755000765000024 013237102475 16562 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Assertion.pm000444000765000024 1312113237102475 21242 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Assertion - Represent a simple assertion. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{\bfoo\b}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents one of the simple assertions; that is, those that are not defined via parentheses. This includes the zero-width assertions C<^>, C<$>, C<\b>, C<\B>, C<\A>, C<\Z>, C<\z> and C<\G>, as well as: =over =item * The C<\z> assertion added in Perl 5.005, =item * The C<\K> assertion added in Perl 5.009005, =item * The C<\b{gcb}> assertion (and friends) added in Perl 5.021009. Similar braced constructions (like C<\b{foo}>) are unknown tokens. =back =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Assertion; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPIx::Regexp::Constant qw{ COOKIE_CLASS LITERAL_LEFT_CURLY_ALLOWED MINIMUM_PERL TOKEN_LITERAL TOKEN_UNKNOWN }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; my @braced_assertions = ( [ qr< \\ [bB] [{] (?: g | gcb | wb | sb ) [}] >smx, '5.021009' ], [ qr< \\ [bB] [{] (?: lb ) [}] >smx, '5.023007' ], [ qr< \\ [bB] [{] .*? [}] >smx, undef, TOKEN_UNKNOWN, { error => 'Unknown bound type' }, ], ); sub perl_version_introduced { my ( $self ) = @_; return ( $self->{perl_version_introduced} ||= $self->_perl_version_introduced() ); } { my %perl_version_introduced = ( '\\K' => '5.009005', '\\z' => '5.005', ); sub _perl_version_introduced { my ( $self ) = @_; my $content = $self->content(); foreach my $item ( @braced_assertions ) { $content =~ m/ \A $item->[0] \z /smx and return $item->[1]; } return $perl_version_introduced{ $content } || MINIMUM_PERL; } } { my %explanation = ( '$' => 'Assert position is at end of string or newline', '\\A' => 'Assert position is at beginning of string', '\\B' => 'Assert position is not at word/nonword boundary', '\\B{gcb}' => 'Assert position is not at grapheme cluster boundary', '\\B{g}' => 'Assert position is not at grapheme cluster boundary', '\\B{lb}' => 'Assert position is not at line boundary', '\\B{sb}' => 'Assert position is not at sentence boundary', '\\B{wb}' => 'Assert position is not at word boundary', '\\G' => 'Assert position is at pos()', '\\K' => 'In s///, keep everything before the \\K', '\\Z' => 'Assert position is at end of string, or newline before end', '\\b' => 'Assert position is at word/nonword boundary', '\\b{gcb}' => 'Assert position is at grapheme cluster boundary', '\\b{g}' => 'Assert position is at grapheme cluster boundary', '\\b{lb}' => 'Assert position is at line boundary', '\\b{sb}' => 'Assert position is at sentence boundary', '\\b{wb}' => 'Assert position is at word boundary', '\\z' => 'Assert position is at end of string', '^' => 'Assert position is at beginning of string or after newline', ); sub __explanation { return \%explanation; } } # An un-escaped literal left curly bracket can always follow this # element. sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_ALLOWED; } # By logic we should handle '$' here. But # PPIx::Regexp::Token::Interpolation needs to process it to see if it is # a sigil. If it is not, that module is expected to make it into an # assertion. This is to try to keep the order in which the tokenizers # are called non-critical, and try to keep all processing for a # character in one place. Except for the back slash, which gets in # everywhere. # ## my %assertion = map { $_ => 1 } qw{ ^ $ }; my %assertion = map { $_ => 1 } qw{ ^ }; my %escaped = map { $_ => 1 } qw{ b B A Z z G K }; sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; # Inside a character class, these are all literals. my $make = $tokenizer->cookie( COOKIE_CLASS ) ? TOKEN_LITERAL : __PACKAGE__; # '^' and '$'. Or at least '^'. See note above for '$'. $assertion{$character} and return $tokenizer->make_token( 1, $make ); $character eq '\\' or return; defined ( my $next = $tokenizer->peek( 1 ) ) or return; # Handle assertions of the form \b{gcb} and friends, introduced in # Perl 5.21.9. These are not recognized inside square bracketed # character classes, where \b is not an assertion but a backspace # character. if ( __PACKAGE__ eq $make ) { # Only outside [...] foreach my $item ( @braced_assertions ) { my $end = $tokenizer->find_regexp( qr/ \A $item->[0] /smx ) or next; $item->[2] or return $end; return $tokenizer->make_token( $end, $item->[2], $item->[3] ); } } $escaped{$next} and return $tokenizer->make_token( 2, $make ); return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Backreference.pm000444000765000024 1317513237102475 22023 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Backreference - Represent a back reference =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(foo|bar)baz\1}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents back references of all sorts, both the traditional numbered variety and the Perl 5.010 named kind. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Backreference; use strict; use warnings; use base qw{ PPIx::Regexp::Token::Reference }; use Carp qw{ confess }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL RE_CAPTURE_NAME TOKEN_LITERAL TOKEN_UNKNOWN }; use PPIx::Regexp::Util qw{ __to_ordinal_en }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub explain { my ( $self ) = @_; $self->is_named() and return sprintf q, $self->name(); $self->is_relative() and return sprintf q, __to_ordinal_en( - $self->number() ), $self->absolute(); return sprintf q, $self->absolute(); } { my %perl_version_introduced = ( g => '5.009005', # \g1 \g-1 \g{1} \g{-1} k => '5.009005', # \k \k'name' '?' => '5.009005', # (?P=name) (PCRE/Python) ); sub perl_version_introduced { my ( $self ) = @_; return $perl_version_introduced{substr( $self->content(), 1, 1 )} || MINIMUM_PERL; } } my @external = ( # Recognition used externally [ qr{ \A \( \? P = ( @{[ RE_CAPTURE_NAME ]} ) \) }smxo, { is_named => 1 }, ], ); my @recognize_regexp = ( # recognition used internally [ qr{ \A \\ (?: # numbered (including relative) ( \d+ ) | g (?: ( -? \d+ ) | \{ ( -? \d+ ) \} ) ) }smx, { is_named => 0 }, ], [ qr{ \A \\ (?: # named g [{] ( @{[ RE_CAPTURE_NAME ]} ) [}] | k (?: \< ( @{[ RE_CAPTURE_NAME ]} ) \> | # named with angles ' ( @{[ RE_CAPTURE_NAME ]} ) ' ) # or quotes ) }smxo, { is_named => 1 }, ], ); my %recognize = ( regexp => \@recognize_regexp, repl => [ [ qr{ \A \\ ( \d+ ) }smx, { is_named => 0 } ], ], ); # This must be implemented by tokens which do not recognize themselves. # The return is a list of list references. Each list reference must # contain a regular expression that recognizes the token, and optionally # a reference to a hash to pass to make_token as the class-specific # arguments. The regular expression MUST be anchored to the beginning of # the string. sub __PPIX_TOKEN__recognize { return __PACKAGE__->isa( scalar caller ) ? ( @external, @recognize_regexp ) : ( @external ); } sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; # PCRE/Python back references are handled in # PPIx::Regexp::Token::Structure, because they are parenthesized. # All the other styles are escaped. $character eq '\\' or return; foreach ( @{ $recognize{$tokenizer->get_mode()} } ) { my ( $re, $arg ) = @{ $_ }; my $accept = $tokenizer->find_regexp( $re ) or next; my %arg = ( %{ $arg }, tokenizer => $tokenizer ); return $tokenizer->make_token( $accept, __PACKAGE__, \%arg ); } return; } sub __PPIX_TOKENIZER__repl { my ( undef, $tokenizer ) = @_; # Invocant, $character unused $tokenizer->interpolates() or return; goto &__PPIX_TOKENIZER__regexp; } # Called by the lexer to disambiguate between captures, literals, and # whatever. We have to return the number of tokens reblessed to # TOKEN_UNKNOWN (i.e. either 0 or 1) because we get called after the # parse is finalized. sub __PPIX_LEXER__rebless { my ( $self, %arg ) = @_; # Handle named back references if ( $self->is_named() ) { $arg{capture_name}{$self->name()} and return 0; return $self->__error(); } # Get the absolute capture group number. my $absolute = $self->absolute(); # If it is zero or negative, we have a relateive reference to a # non-existent capture group. $absolute <= 0 and return $self->__error(); # If the absolute number is less than or equal to the maximum # capture group number, we are good. $absolute <= $arg{max_capture} and return 0; # It's not a valid capture. If it's an octal literal, rebless it so. # Note that we can't rebless single-digit numbers, since they can't # be octal literals. my $content = $self->content(); if ( $content =~ m/ \A \\ [0-7]{2,} \z /smx ) { bless $self, TOKEN_LITERAL; return 0; } # Anything else is an error. return $self->__error(); } sub __error { my ( $self, $msg ) = @_; defined $msg or $msg = 'No corresponding capture group'; $self->{error} = $msg; bless $self, TOKEN_UNKNOWN; return 1; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Backtrack.pm000444000765000024 720513237102475 21146 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Backtrack - Represent backtrack control. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(*ACCEPT)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents one of the backtrack controls. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Backtrack; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; { my %explanation = ( ACCEPT => 'Causes match to succeed at the point of the (*ACCEPT)', COMMIT => 'Causes match failure when backtracked into on failure', FAIL => 'Always fails, forcing backtrack', MARK => 'Name branches of alternation, target for (*SKIP)', PRUNE => 'Prevent backtracking past here on failure', SKIP => 'Like (*PRUNE) but also discards match to this point', THEN => 'Force next alternation on failure', ); sub explain { my ( $self ) = @_; my $verb = $self->verb(); defined( my $expl = $explanation{$verb} ) or return $self->__no_explanation(); return $expl; } my %synonym = ( '' => 'MARK', F => 'FAIL', ); =head2 arg This method returns the backtrack control argument specified by the element. This is the text after the first colon (C<':'>), or the empty string (C<''>) if none was specified. =cut sub arg { my ( $self ) = @_; my $content = $self->content(); $content =~ s/ [^:]* //smx; # ( $content =~ s/ \) //smx; return $content; } =head2 verb This method returns the backtrack control verb represented by the element. This is the text up to but not including the first colon (C<':'>) if any. If the element specifies C<''> or C<'F">, this method will return C<'MARK'> or C<'FAIL'>, respectively. =cut sub verb { my ( $self ) = @_; my $content = $self->content(); $content =~ s/ \( \* //smx; $content =~ s/ [:)] .* //smx; defined( my $syn = $synonym{$content} ) or return $content; return $syn; } } sub perl_version_introduced { return '5.009005'; } # This must be implemented by tokens which do not recognize themselves. # The return is a list of list references. Each list reference must # contain a regular expression that recognizes the token, and optionally # a reference to a hash to pass to make_token as the class-specific # arguments. The regular expression MUST be anchored to the beginning of # the string. sub __PPIX_TOKEN__recognize { return ( [ qr{ \A \( \* [^\)]* \) }smx ] ); } # This class gets recognized by PPIx::Regexp::Token::Structure as part # of its left parenthesis processing. =begin comment sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; return $character eq 'x' ? 1 : 0; } =end comment =cut 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/CharClass.pm000444000765000024 421313237102475 21120 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::CharClass - Represent a character class =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{\w}smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L and L. =head1 DESCRIPTION This class represents a character class. It is not intended that this class be instantiated; it simply serves to identify a character class in the class hierarchy, and provide any common methods that might become useful. =head1 METHODS This class provides the following public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::CharClass; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; ##=head2 is_case_sensitive ## ##This method returns true if the character class is case-sensitive (that ##is, if it may match or not based on the case of the string being ##matched), false (but defined) if it is not, and simply returns (giving ##C in scalar context and an empty list in list context) if the ##case-sensitivity can not be determined. ## ##=cut ## ##sub is_case_sensitive { ## return; ##} 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Code.pm000444000765000024 1012113237102475 20142 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Code - Represent a chunk of Perl embedded in a regular expression. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?{print "hello sailor\n"})}smx')->print; =head1 INHERITANCE C is a L. C is the parent of L. =head1 DESCRIPTION This class represents a chunk of Perl code embedded in a regular expression. Specifically, it results from parsing things like (?{ code }) (??{ code }) or from the replacement side of an s///e. Technically, interpolations are also code, but they parse differently and therefore end up in a different token. This token may not appear inside a regex set (i.e. C<(?[ ... ])>. If found, it will become a C. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::Code; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPI::Document; use PPIx::Regexp::Constant qw{ COOKIE_REGEX_SET }; use PPIx::Regexp::Util qw{ __instance }; our $VERSION = '0.055'; use constant TOKENIZER_ARGUMENT_REQUIRED => 1; use constant VERSION_WHEN_IN_REGEX_SET => undef; sub __new { my ( $class, $content, %arg ) = @_; defined $arg{perl_version_introduced} or $arg{perl_version_introduced} = '5.005'; my $self = $class->SUPER::__new( $content, %arg ); # TODO sort this out, since Token::Interpolation is a subclass, and # those are legal in regex sets if ( $arg{tokenizer}->cookie( COOKIE_REGEX_SET ) ) { my $ver = $self->VERSION_WHEN_IN_REGEX_SET() or return $self->__error( 'Code token not valid in Regex set' ); $self->{perl_version_introduced} < $ver and $self->{perl_version_introduced} = $ver; } $arg{tokenizer}->__recognize_postderef( $self ) and $self->{perl_version_introduced} < 5.019005 and $self->{perl_version_introduced} = '5.019005'; return $self; } sub content { my ( $self ) = @_; if ( exists $self->{content} ) { return $self->{content}; } elsif ( exists $self->{ppi} ) { return ( $self->{content} = $self->{ppi}->content() ); } else { return; } } sub explain { return 'Perl expression'; } =head2 ppi This convenience method returns the L representing the content. This document should be considered read only. =cut sub ppi { my ( $self ) = @_; if ( exists $self->{ppi} ) { return $self->{ppi}; } elsif ( exists $self->{content} ) { return ( $self->{ppi} = PPI::Document->new( \($self->{content}), readonly => 1 ) ); } else { return; } } # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { no warnings qw{ qw }; ## no critic (ProhibitNoWarnings) my %accept = map { $_ => 1 } qw{ $ $# @ % & * }; # Say what casts are accepted, since not all are in am # interpolation. sub __postderef_accept_cast { return \%accept; } } sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; $character eq '{' or return; my $offset = $tokenizer->find_matching_delimiter() or return; return $offset + 1; # to include the closing delimiter. } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Comment.pm000444000765000024 456313237102475 20667 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Comment - Represent a comment. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo(?#bar)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a comment - both parenthesized comments (i.e. C<< (?# this is a comment ) >> and the /x mode end-of-line comments. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Comment; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; sub significant { return; } sub comment { return 1; } sub explain { return 'Comment'; } # This must be implemented by tokens which do not recognize themselves. # The return is a list of list references. Each list reference must # contain a regular expression that recognizes the token, and optionally # a reference to a hash to pass to make_token as the class-specific # arguments. The regular expression MUST be anchored to the beginning of # the string. sub __PPIX_TOKEN__recognize { return ( [ qr{ \A \( \? \# [^\)]* \) }smx ] ); } # We anticipate that these tokens will be generated by other classes: # PPIx::Regexp::Token::Structure for parenthesized comments, and # PPIx::Regexp::Token::Literal for end-of-line /x mode comments. =begin comment sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; return $character eq 'x' ? 1 : 0; } =end comment =cut 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Condition.pm000444000765000024 703413237102475 21207 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Condition - Represent the condition of a switch =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?(1)foo|bar)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents the condition portion of a switch or conditional expression, provided that condition is reasonably represented as a token. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Condition; use strict; use warnings; use base qw{ PPIx::Regexp::Token::Reference }; use PPIx::Regexp::Constant qw{ RE_CAPTURE_NAME }; our $VERSION = '0.055'; { my %explanation = ( '(DEFINE)' => 'Define a group to be recursed into', '(R)' => 'True if recursing', ); sub explain { my ( $self ) = @_; my $content = $self->content(); if ( defined( my $expl = $explanation{$content} ) ) { return $expl; } if ( $content =~ m/ \A [(] R /smx ) { # ) $self->is_named() and return sprintf q, $self->name(); return sprintf q, $self->absolute(); } $self->is_named() and return sprintf q, $self->name(); return sprintf q, $self->absolute(); } } sub perl_version_introduced { my ( $self ) = @_; $self->content() =~ m/ \A [(] \d+ [)] \z /smx and return '5.005'; return '5.009005'; } my @recognize = ( [ qr{ \A \( (?: ( \d+ ) | R (\d+) ) \) }smx, { is_named => 0 } ], [ qr{ \A \( R \) }smx, { is_named => 0, capture => '0' } ], [ qr{ \A \( (?: < ( @{[ RE_CAPTURE_NAME ]} ) > | ' ( @{[ RE_CAPTURE_NAME ]} ) ' | R & ( @{[ RE_CAPTURE_NAME ]} ) ) \) }smxo, { is_named => 1} ], [ qr{ \A \( DEFINE \) }smx, { is_named => 0, capture => '0' } ], ); # This must be implemented by tokens which do not recognize themselves. # The return is a list of list references. Each list reference must # contain a regular expression that recognizes the token, and optionally # a reference to a hash to pass to make_token as the class-specific # arguments. The regular expression MUST be anchored to the beginning of # the string. sub __PPIX_TOKEN__recognize { return @recognize; } # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer ) = @_; # Invocant, $character unused foreach ( @recognize ) { my ( $re, $arg ) = @{ $_ }; my $accept = $tokenizer->find_regexp( $re ) or next; return $tokenizer->make_token( $accept, __PACKAGE__, $arg ); } return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Control.pm000444000765000024 1232613237102475 20721 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Control - Case and quote control. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{\Ufoo\E}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents the case and quote controls. These apply when the regular expression is compiled, changing the actual expression generated. For example print qr{\Ufoo\E}, "\n" prints (?-xism:FOO) =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Control; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPIx::Regexp::Constant qw{ COOKIE_QUOTE MINIMUM_PERL TOKEN_LITERAL TOKEN_UNKNOWN }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { my %explanation = ( '\\E' => 'End of interpolation control', '\\F' => 'Fold case until \\E', '\\L' => 'Lowercase until \\E', '\\Q' => 'Quote metacharacters until \\E', '\\U' => 'Uppercase until \\E', '\\l' => 'Lowercase next character', '\\u' => 'Uppercase next character', ); sub __explanation { return \%explanation; } } { my %version_introduced = ( '\\F' => '5.015008', ); sub perl_version_introduced { my ( $self ) = @_; my $content = $self->content(); defined $version_introduced{$content} and return $version_introduced{$content}; return MINIMUM_PERL; } } my %is_control = map { $_ => 1 } qw{ l u L U Q E F }; my %cookie_slot = ( Q => 'quote', E => 'end', U => 'case', L => 'case', F => 'case', ); use constant CONTROL_MASK_QUOTE => 1 << 1; my %cookie_mask = ( case => 1 << 0, end => 0, # must be 0. quote => CONTROL_MASK_QUOTE, ); sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; # If we are inside a quote sequence, we want to make literals out of # all the characters we reject; otherwise we just want to return # nothing. my $in_quote = $tokenizer->cookie( COOKIE_QUOTE ) || do { my @stack = ( { mask => 0, reject => sub { return; } } ); $tokenizer->cookie( COOKIE_QUOTE, sub { return \@stack } ); }; my $cookie_stack = $in_quote->( $tokenizer ); my $reject = $cookie_stack->[-1]{reject}; # We are not interested in anything that is not escaped. $character eq '\\' or return $reject->( 1 ); # We need to see what the next character is to figure out what to # do. If there is no next character, we do not know what to call the # back slash. my $control = $tokenizer->peek( 1 ) or return $reject->( 1, TOKEN_UNKNOWN, { error => 'Trailing back slash' }, ); # We reject any escapes that do not represent controls. $is_control{$control} or return $reject->( 2 ); # Anything left gets made into a token now, to avoid its processing # by the cookie we may make. my $token = $tokenizer->make_token( 2 ); # \U, \L, and \F supersede each other, but they stack with \Q. So we # need to track that behavior, so that we know what to do when we # hit a \E. # TODO if we wanted we could actually track which (if any) of \U, \L # and \F is in effect, and make that an attribute of any literals # made. if ( my $slot = $cookie_slot{$control} ) { if ( my $mask = $cookie_mask{$slot} ) { # We need another stack entry only if the current slot # ('case' or 'quote') is not occupied unless ( $mask & $cookie_stack->[-1]{mask} ) { # Clone the previous entry. push @{ $cookie_stack }, { %{ $cookie_stack->[-1] } }; # Set the mask to show this slot is occupied $cookie_stack->[-1]{mask} |= $mask; # Code to call when this tokenizer rejects a token $cookie_stack->[-1]{reject} = ( $mask & CONTROL_MASK_QUOTE ) ? sub { my ( $size, $class ) = @_; return $tokenizer->make_token( $size, $class || TOKEN_LITERAL ); } : $cookie_stack->[0]{reject}; } # TODO if I want to try to track what controls are in effect # where. # Record the specific content of the current slot # $cookie_stack->[-1]{$slot} = $control; } else { # \E - pop data, but don't leave empty. @{ $cookie_stack } > 1 and pop @{ $cookie_stack }; } } # Return our token. return $token; } sub __PPIX_TOKENIZER__repl { my ( undef, $tokenizer ) = @_; # Invocant, $character unused $tokenizer->interpolates() and goto &__PPIX_TOKENIZER__regexp; return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Delimiter.pm000444000765000024 325713237102475 21202 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Delimiter - Represent the delimiters of the regular expression =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This token represents the delimiters of the regular expression. Since the tokenizer has to figure out where these are anyway, this class is used to give the lexer a hint about what is going on. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Delimiter; use strict; use warnings; use base qw{ PPIx::Regexp::Token::Structure }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub explain { return 'Regular expression or replacement string delimiter'; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Greediness.pm000444000765000024 501613237102475 21347 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Greediness - Represent a greediness qualifier. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo*+}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a greediness qualifier for the preceding quantifier. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::Greediness; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; { my %explanation = ( '+' => 'match longest string and give nothing back', '?' => 'match shortest string first', ); sub __explanation { return \%explanation; } } my %greediness = ( '?' => MINIMUM_PERL, '+' => '5.009005', ); =head2 could_be_greediness PPIx::Regexp::Token::Greediness->could_be_greediness( '?' ); This method returns true if the given string could be a greediness indicator; that is, if it is '+' or '?'. =cut sub could_be_greediness { my ( undef, $string ) = @_; # Invocant unused return $greediness{$string}; } sub perl_version_introduced { my ( $self ) = @_; return $greediness{ $self->content() } || MINIMUM_PERL; } sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; # Invocant, $char_type unused $tokenizer->prior_significant_token( 'is_quantifier' ) or return; $greediness{$character} or return; return length $character; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType.pm000444000765000024 1305313237102475 21235 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType - Represent a grouping parenthesis type. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?i:foo)}smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L, L, L, L, L, L, L and L. =head1 DESCRIPTION This class represents any of the magic sequences of characters that can follow an open parenthesis. This particular class is intended to be abstract. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::GroupType; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; =head2 __defining_string my $string = $class->__defining_string(); This method is private to the C package, and is documented for the author's benefit only. It may be changed or revoked without notice. This method returns an array of strings that define the specific group type. These strings will normally start with C<'?'>. Optionally, the first returned item may be a hash reference. The only supported key is C<{suffix}>, which is a string to be suffixed to each of the regular expressions made by C<__make_group_type_matcher()> out of the defining strings, inside a C<(?= ... )>, so that it is not included in the match. This method B be overridden, unless C<__make_group_type_matcher()> is. The override B return the same thing each time, since the results of C<__make_group_type_matcher()> are cached. =cut sub __defining_string { require Carp; Carp::confess( 'Programming error - __defining_string() must be overridden' ); } =head2 __make_group_type_matcher my $hash_ref = $class->__make_group_type_matcher(); This method is private to the C package, and is documented for the author's benefit only. It may be changed or revoked without notice. This method returns a reference to a hash. The keys are regexp delimiter characters which appear in the defining strings for the group type. For each key, the value is a reference to an array of C objects, properly escaped for the key character. Key C<''> provides the regular expressions to be used if the regexp delimiter does not appear in any of the defining strings. If this method is overridden by the subclass, method C<__defining_string()> need not be, unless the overridden C<__make_group_type_matcher()> calls C<__defining_string()>. =cut sub __make_group_type_matcher { my ( $class ) = @_; my @defs = $class->__defining_string(); my $opt = ref $defs[0] ? shift @defs : {}; my $suffix = defined $opt->{suffix} ? qr/ (?= \Q$opt->{suffix}\E ) /smx : ''; my %seen; my @chars = grep { ! $seen{$_}++ } split qr{}smx, join '', @defs; my %rslt; foreach my $str ( @defs ) { push @{ $rslt{''} ||= [] }, qr{ \A \Q$str\E $suffix }smx; foreach my $chr ( @chars ) { ( my $expr = $str ) =~ s/ (?= \Q$chr\E ) /\\/smxg; push @{ $rslt{$chr} ||= [] }, qr{ \A \Q$expr\E $suffix }smx; } } return \%rslt; } =head2 __match_setup $class->__match_setup( $tokenizer ); This method is private to the C package, and is documented for the author's benefit only. It may be changed or revoked without notice. This method performs whatever setup is needed once it is determined that the given group type has been detected. This method is called only if the class matched at the current position in the string being parsed. It must perform whatever extra setup is needed for the match. It returns nothing. This method need not be overridden. The default does nothing. =cut sub __match_setup { return; } my %matcher; sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer ) = @_; # $character unused my $mtch = $matcher{$class} ||= $class->__make_group_type_matcher(); my $re_list = $mtch->{ $tokenizer->get_start_delimiter() } || $mtch->{''}; foreach my $re ( @{ $re_list } ) { my $accept = $tokenizer->find_regexp( $re ) or next; $class->__match_setup( $tokenizer ); return $accept; } return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Interpolation.pm000444000765000024 3126413237102475 22132 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Interpolation - Represent an interpolation in the PPIx::Regexp package. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new('qr{$foo}smx')->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a variable interpolation into a regular expression. In the L the C<$foo> would be represented by an object of this class. =head1 METHODS This class provides the following public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Interpolation; use strict; use warnings; use base qw{ PPIx::Regexp::Token::Code }; use Carp qw{ confess }; use PPI::Document; use PPIx::Regexp::Constant qw{ COOKIE_CLASS COOKIE_REGEX_SET TOKEN_LITERAL MINIMUM_PERL }; our $VERSION = '0.055'; use constant VERSION_WHEN_IN_REGEX_SET => '5.017009'; sub __new { my ( $class, $content, %arg ) = @_; defined $arg{perl_version_introduced} or $arg{perl_version_introduced} = MINIMUM_PERL; my $self = $class->SUPER::__new( $content, %arg ); return $self; } # Return true if the token can be quantified, and false otherwise # This can be quantified because it might interpolate a quantifiable # token. Of course, it might not, but we need to be permissive here. # sub can_be_quantified { return }; # We overrode this in PPIx::Regexp::Token::Code, since (?{...}) did not # appear until Perl 5.5. But interpolation has been there since the # beginning, so we have to override again. This turns out to be OK, # though, because while Regex Sets were introduced in 5.17.8, # interpolation inside them was not introduced until 5.17.9. sub perl_version_introduced { my ( $self ) = @_; return $self->{perl_version_introduced}; } =head2 ppi This convenience method returns the L representing the content. This document should be considered read only. Note that the content of the returned L may not be the same as the content of the original C. This can happen because interpolated variable names may be enclosed in curly brackets, but this does not happen in normal code. For example, in C, the content of the C object will be C<'${foo}'>, but the content of the C will be C<'$foo'>. =cut sub ppi { my ( $self ) = @_; if ( exists $self->{ppi} ) { return $self->{ppi}; } elsif ( exists $self->{content} ) { ( my $code = $self->{content} ) =~ s/ \A ( [\@\$] ) [{] ( .* ) [}] \z /$1$2/smx; return ( $self->{ppi} = PPI::Document->new( \$code, readonly => 1 ) ); } else { return; } } # Match the beginning of an interpolation. my $interp_re = qr{ \A (?= [\@\$]? \$ [-\w&`'+^./\\";%=~:?!\@\$<>\[\]\{\},#] | \@ [\w\{] ) }smx; # Match bracketed interpolation my $brkt_interp_re = qr{ \A (?: [\@\$] \$* [#]? \$* [\{] (?: [][\-&`'+,^./\\";%=:?\@\$<>,#] | \^? \w+ (?: :: \w+ )* ) [\}] | \@ [\{] \w+ (?: :: \w+ )* [\}] ) }smx; # We pull out the logic of finding and dealing with the interpolation # into a separate subroutine because if we fail to find an interpolation # we want to do something with the sigils. my %allow_subscript_based_on_cast_symbol = ( q<$#> => 0, q<$> => 1, q<@> => 1, ); sub _interpolation { my ( $class, $tokenizer, undef, $in_regexp ) = @_; # $character unused # If the regexp does not interpolate, bail now. $tokenizer->interpolates() or return; # If we're a bracketed interpolation, just accept it if ( my $len = $tokenizer->find_regexp( $brkt_interp_re ) ) { return $len; } # Make sure we start off plausibly defined $tokenizer->find_regexp( $interp_re ) or return; # See if PPI can figure out what we have my $doc = $tokenizer->ppi_document() or return; # Get the first statement to work on. my $stmt = $doc->find_first( 'PPI::Statement' ) or return; my @accum; # The elements of the interpolation my $allow_subscript; # Assume no subscripts allowed # Find the beginning of the interpolation my $next = $stmt->schild( 0 ) or return; # The interpolation should start with if ( $next->isa( 'PPI::Token::Symbol' ) ) { # A symbol push @accum, $next; $allow_subscript = 1; # Subscripts are allowed } elsif ( $next->isa( 'PPI::Token::Cast' ) ) { # Or a cast followed by a block push @accum, $next; $next = $next->next_sibling() or return; if ( $next->isa( 'PPI::Token::Symbol' ) ) { defined ( $allow_subscript = $allow_subscript_based_on_cast_symbol{ $accum[-1]->content() } ) or return; push @accum, $next; } elsif ( $next->isa( 'PPI::Structure::Block' ) ) { push @accum, $next; } else { return; } } elsif ( $next->isa( 'PPI::Token::ArrayIndex' ) ) { # Or an array index push @accum, $next; } else { # None others need apply. return; } # The interpolation _may_ be subscripted. If so ... { # Only accept a subscript if wanted and available $allow_subscript and $next = $next->snext_sibling() or last; # Accept an optional dereference operator. my @subscr; if ( $next->isa( 'PPI::Token::Operator' ) ) { $next->content() eq '->' or last; push @subscr, $next; $next = $next->next_sibling() or last; # postderef was introduced in 5.19.5, per perl5195delta. if ( my $deref = $tokenizer->__recognize_postderef( __PACKAGE__, $next ) ) { push @accum, @subscr, $deref; last; } } # Accept only a subscript $next->isa( 'PPI::Structure::Subscript' ) or last; # The subscript must have a closing delimiter. $next->finish() or last; # If we are in a regular expression rather than a replacement # string, screen the subscript for content, since [] could be a # character class, and {} could be a quantifier. The perlop docs # say that Perl applies undocumented heuristics subject to # change without notice to figure this out. So we do our poor # best to be heuristical and undocumented. not $in_regexp or $class->_subscript( $next ) or last; # If we got this far, accept the subscript and try for another # one. push @accum, @subscr, $next; redo; } # Compute the length of all the PPI elements accumulated, and return # it. my $length = 0; foreach ( @accum ) { $length += ref $_ ? length $_->content() : $_; } return $length; } { no warnings qw{ qw }; ## no critic (ProhibitNoWarnings) my %accept = map { $_ => 1 } qw{ $ $# @ }; sub __postderef_accept_cast { return \%accept; } } { my %allowed = ( '[' => '_square', '{' => '_curly', ); sub _subscript { my ( $class, $struct ) = @_; # We expect to have a left delimiter, which is either a '[' or a # '{'. my $left = $struct->start() or return; my $lc = $left->content(); my $handler = $allowed{$lc} or return; # We expect a single child, which is a PPI::Statement ( my @kids = $struct->schildren() ) == 1 or return; $kids[0]->isa( 'PPI::Statement' ) or return; # We expect the statement to have at least one child. ( @kids = $kids[0]->schildren() ) or return; return $class->$handler( @kids ); } } # Return true if we think a curly-bracketed subscript is really a # subscript, rather than a quantifier. # Called as $class->$handler( ... ) above sub _curly { ## no critic (ProhibitUnusedPrivateSubroutines) my ( undef, @kids ) = @_; # Invocant unused # If the first child is a word, and either it is an only child or # the next child is the fat comma operator, we accept it as a # subscript. if ( $kids[0]->isa( 'PPI::Token::Word' ) ) { @kids == 1 and return 1; $kids[1]->isa( 'PPI::Token::Operator' ) and $kids[1]->content() eq '=>' and return 1; } # If the first child is a symbol, if ( @kids && $kids[0]->isa( 'PPI::Token::Symbol' ) ) { # Accept it if it is the only child @kids == 1 and return 1; # Accept it if there are exactly two children and the second is # a subscript. @kids == 2 and $kids[1]->isa( 'PPI::Structure::Subscript' ) and return 1; } # We reject anything else. return; } # Return true if we think a square-bracketed subscript is really a # subscript, rather than a character class. # Called as $class->$handler( ... ) above sub _square { ## no critic (ProhibitUnusedPrivateSubroutines) my ( undef, @kids ) = @_; # Invocant unused # We expect to have either a number or a symbol as the first # element. $kids[0]->isa( 'PPI::Token::Number' ) and return 1; $kids[0]->isa( 'PPI::Token::Symbol' ) and return 1; # Anything else is rejected. return; } # Alternate classes for the sigils, depending on whether we are in a # character class (index 1) or not (index 0). my %sigil_alternate = ( '$' => [ 'PPIx::Regexp::Token::Assertion', TOKEN_LITERAL ], '@' => [ TOKEN_LITERAL, TOKEN_LITERAL ], ); sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; exists $sigil_alternate{$character} or return; if ( my $accept = $class->_interpolation( $tokenizer, $character, 1 ) ) { return $accept; } my $alternate = $sigil_alternate{$character} or return; return $tokenizer->make_token( 1, $alternate->[$tokenizer->cookie( COOKIE_CLASS ) ? 1 : 0 ] ); } sub __PPIX_TOKENIZER__repl { my ( $class, $tokenizer, $character ) = @_; exists $sigil_alternate{$character} or return; if ( my $accept = $class->_interpolation( $tokenizer, $character, 0 ) ) { return $accept; } return $tokenizer->make_token( 1, TOKEN_LITERAL ); } 1; __END__ =begin comment Interpolation notes: $ perl -E '$foo = "\\w"; $bar = 3; say qr{$foo{$bar}}' (?-xism:) white2:~/Code/perl/PPIx-Regexp.new tom 22:50:33 $ perl -E '$foo = "\\w"; $bar = 3; say qr{foo{$bar}}' (?-xism:foo{3}) white2:~/Code/perl/PPIx-Regexp.new tom 22:50:59 $ perl -E '$foo = "\\w"; $bar = 3; %foo = {baz => 42}; say qr{$foo{$bar}}' (?-xism:) white2:~/Code/perl/PPIx-Regexp.new tom 22:51:38 $ perl -E '$foo = "\\w"; $bar = 3; %foo = {baz => 42}; say qr{$foo}' (?-xism:\w) white2:~/Code/perl/PPIx-Regexp.new tom 22:51:50 $ perl -E '$foo = "\\w"; $bar = 3; %foo = {baz => 42}; say qr{$foo{baz}}' (?-xism:) white2:~/Code/perl/PPIx-Regexp.new tom 22:52:49 $ perl -E '$foo = "\\w"; $bar = 3; %foo = {baz => 42}; say qr{${foo}{baz}}' (?-xism:\w{baz}) white2:~/Code/perl/PPIx-Regexp.new tom 22:54:07 $ perl -E '$foo = "\\w"; $bar = 3; %foo = {baz => 42}; say qr{${foo}{$bar}}' (?-xism:\w{3}) The above makes me think that Perl is extremely reluctant to understand an interpolation followed by curlys as a hash dereference. In fact, only when the interpolation was what PPI calls a block was it understood at all. $ perl -E '$foo = { bar => 42 }; say qr{$foo->{bar}};' (?-xism:42) $ perl -E '$foo = { bar => 42 }; say qr{$foo->{baz}};' (?-xism:) On the other hand, Perl seems to be less reluctant to accept an explicit dereference as a hash dereference. $ perl -E '$foo = "\\w"; $bar = 3; @foo = (42); say qr{$foo}' (?-xism:\w) white2:~/Code/perl/PPIx-Regexp.new tom 22:58:20 $ perl -E '$foo = "\\w"; $bar = 3; @foo = (42); say qr{$foo[0]}' (?-xism:42) white2:~/Code/perl/PPIx-Regexp.new tom 22:58:28 $ perl -E '$foo = "\\w"; $bar = 3; @foo = (42); say qr{$foo[$bar]}' (?-xism:) white2:~/Code/perl/PPIx-Regexp.new tom 22:58:43 $ perl -E '$foo = "\\w"; $bar = 0; @foo = (42); say qr{$foo[$bar]}' (?-xism:42) The above makes it somewhat easier to get $foo[$bar] interpreted as an array dereference, but it appears to make use of information that is not available to a static analysis, such as whether $foo[$bar] exists. Actually, the above suggests a strategy: a subscript of any kind is to be accepted as a subscript if it looks like \[\d+\], \[\$foo\], \{\w+\}, or \{\$foo\}. Otherwise, accept it as a character class or a quantifier depending on the delimiter. Obviously when I bring PPI to bear I will have to keep track of '->' operators before subscripts, and shed them from the interpolation as well if the purported subscript does not pass muster. =end comment =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Literal.pm000444000765000024 3535513237102475 20704 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Literal - Represent a literal character =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a literal character, no matter how specified. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::Literal; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPIx::Regexp::Constant qw{ COOKIE_CLASS COOKIE_REGEX_SET LITERAL_LEFT_CURLY_ALLOWED LITERAL_LEFT_CURLY_REMOVED_PHASE_1 LITERAL_LEFT_CURLY_REMOVED_PHASE_2 MINIMUM_PERL MSG_PROHIBITED_BY_STRICT TOKEN_UNKNOWN }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub explain { return 'Literal character'; } sub perl_version_introduced { my ( $self ) = @_; exists $self->{perl_version_introduced} and return $self->{perl_version_introduced}; ( my $content = $self->content() ) =~ m/ \A \\ o /smx and return ( $self->{perl_version_introduced} = '5.013003' ); $content =~ m/ \A \\ N [{] U [+] /smx and return ( $self->{perl_version_introduced} = '5.008' ); $content =~ m/ \A \\ x [{] /smx # } and return ( $self->{perl_version_introduced} = '5.006' ); $content =~ m/ \A \\ N /smx and return ( $self->{perl_version_introduced} = '5.006001' ); return ( $self->{perl_version_introduced} = MINIMUM_PERL ); } { my %removed = ( q<{> => sub { my ( $self ) = @_; # Un-escaped literal left curlys are always allowed when # they begin the regexp or the group. my $prev = $self->sprevious_sibling() or return LITERAL_LEFT_CURLY_ALLOWED; return $prev->__following_literal_left_curly_disallowed_in(); }, ); sub perl_version_removed { my ( $self ) = @_; exists $self->{perl_version_removed} and return $self->{perl_version_removed}; my $code; return ( $self->{perl_version_removed} = ( $code = $removed{$self->content()} ) ? scalar $code->( $self ) : undef ); } } # Some characters may or may not be literals depending on whether we are # inside a character class. The following hash identifies those # characters and says what we should return when outside (index 0) or # inside (index 1) a character class, as judged by the presence of the # relevant cookie. my %double_agent = ( '.' => [ undef, 1 ], '*' => [ undef, 1 ], '?' => [ undef, 1 ], '+' => [ undef, 1 ], '-' => [ 1, undef ], '|' => [ undef, 1 ], ); # These are the characters that other external tokenizers need to see, # or at least that we need to take a closer look at. All others can be # unconditionally made into single-character literals. my %extra_ordinary = map { $_ => 1 } split qr{}smx, '$@*+?.\\(){}[]^|-#'; # $ -> Token::Interpolation, Token::Assertion # @ -> Token::Interpolation # * -> Token::Quantifier # + ? -> Token::Quantifier, Token::Greediness # . -> Token::CharClass::Simple # \ -> Token::Control, Token::CharClass::Simple, Token::Assertion, # Token::Backreference # ( ) { } [ ] -> Token::Structure # ^ -> Token::Assertion # | - -> Token::Operator my %regex_set_operator = map { $_ => 1 } qw{ & + | - ^ ! }; # The regex for the extended white space available under regex sets in # Perl 5.17.8 and in general in perl 5.17.9. I have been unable to get # this to work under Perl 5.6.2, so for that we fall back to ASCII white # space. The stringy eval is because I have been unable to get # satisfaction out of either interpolated characters (in general) or # eval-ed "\N{U+...}" (under 5.6.2) or \x{...} (ditto). # # See PPIx::Regexp::Structure::RegexSet for the documentation of this # mess. # my $white_space_re = $] >= 5.008 ? # 'qr< \\A [\\s\\N{U+0085}\\N{U+200E}\\N{U+200F}\\N{U+2028}\\N{U+2029}]+ >smx' : # 'qr< \\A \\s+ >smx'; # # RT #91798 # The above turns out to be wrong, because \s matches too many # characters. We need the following to get the right match. Note that # \cK was added experimentally in 5.17.0 and made it into 5.18. The \N{} # characters were NOT added (as I originally thought) but were simply # made characters that generated warnings when escaped, in preparation # for adding them. When they actually get added, I will have to add back # the trinary operator. Sigh. # my $white_space_re = 'qr< \A [\t\n\cK\f\r ] >smx'; # # The extended white space characters came back in Perl 5.21.1. my $white_space_re = $] >= 5.008 ? 'qr< \\A [\\t\\n\\cK\\f\\r \\N{U+0085}\\N{U+200E}\\N{U+200F}\\N{U+2028}\\N{U+2029}]+ >smx' : 'qr< \\A [\\t\\n\\cK\\f\\r ]+ >smx'; $white_space_re = eval $white_space_re; ## no critic (ProhibitStringyEval) my %regex_pass_on = map { $_ => 1 } qw{ [ ] ( ) $ \ }; sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; # Invocant, $char_type unused if ( $tokenizer->cookie( COOKIE_REGEX_SET ) ) { # If we're inside a regex set no literals are allowed, but not # all characters that get here are seen as literals. $regex_set_operator{$character} and return $tokenizer->make_token( length $character, 'PPIx::Regexp::Token::Operator' ); my $accept; # As of 5.23.4, only space and horizontal tab are legal white # space inside a bracketed class inside an extended character # class $accept = $tokenizer->find_regexp( $tokenizer->cookie( COOKIE_CLASS ) ? qr{ \A [ \t] }smx : $white_space_re ) and return $tokenizer->make_token( $accept, 'PPIx::Regexp::Token::Whitespace' ); $accept = _escaped( $tokenizer, $character ) and return $accept; $regex_pass_on{$character} and return; # At this point we have a single character which is poised to be # interpreted as a literal. These are not legal in a regex set # except when also in a bracketed class. return $tokenizer->cookie( COOKIE_CLASS ) ? length $character : $tokenizer->make_token( length $character, TOKEN_UNKNOWN, { error => 'Literal not valid in Regex set', }, ); } else { # Otherwise handle the characters that may or may not be # literals depending on whether or not we are in a character # class. if ( my $class = $double_agent{$character} ) { my $inx = $tokenizer->cookie( COOKIE_CLASS ) ? 1 : 0; return $class->[$inx]; } } # If /x is in effect _and_ we are not inside a character class, \s # is whitespace, and '#' introduces a comment. Otherwise they are # both literals. if ( $tokenizer->modifier( 'x*' ) && ! $tokenizer->cookie( COOKIE_CLASS ) ) { my $accept; $accept = $tokenizer->find_regexp( $white_space_re ) and return $tokenizer->make_token( $accept, 'PPIx::Regexp::Token::Whitespace' ); $accept = $tokenizer->find_regexp( qr{ \A \# [^\n]* (?: \n | \z) }smx ) and return $tokenizer->make_token( $accept, 'PPIx::Regexp::Token::Comment' ); } elsif ( $tokenizer->modifier( 'xx' ) && $tokenizer->cookie( COOKIE_CLASS ) ) { my $accept; $accept = $tokenizer->find_regexp( qr{ \A [ \t] }smx ) and return $tokenizer->make_token( $accept, 'PPIx::Regexp::Token::Whitespace', { perl_version_introduced => '5.025009' }, ); } else { ( $character eq '#' || $character =~ m/ \A \s \z /smx ) and return 1; } my $accept; $accept = _escaped( $tokenizer, $character ) and return $accept; # All other characters which are not extra ordinary get accepted. $extra_ordinary{$character} or return 1; return; } =begin comment The following is from perlop: The character following "\c" is mapped to some other character by converting letters to upper case and then (on ASCII systems) by inverting the 7th bit (0x40). The most interesting range is from '@' to '_' (0x40 through 0x5F), resulting in a control character from 0x00 through 0x1F. A '?' maps to the DEL character. On EBCDIC systems only '@', the letters, '[', '\', ']', '^', '_' and '?' will work, resulting in 0x00 through 0x1F and 0x7F. =end comment =cut # Recognize all the escaped constructions that generate literal # characters in one gigantic regexp. Technically \1.. through \7.. are # octal literals too, but we can not disambiguate these from back # references until we know how many there are. So the lexer gets another # dirty job. { my %special = ( '\\N{}' => sub { my ( $tokenizer, $accept ) = @_; $tokenizer->strict() or return $tokenizer->make_token( $accept, 'PPIx::Regexp::Token::NoOp', { perl_version_removed => '5.027001', }, ); return $tokenizer->make_token( $accept, TOKEN_UNKNOWN, { error => join( ' ', 'Empty Unicode character name', MSG_PROHIBITED_BY_STRICT ), perl_version_introduced => '5.023008', perl_version_removed => '5.027001', }, ); }, ); sub _escaped { my ( $tokenizer, $character ) = @_; $character eq '\\' or return; if ( my $accept = $tokenizer->find_regexp( qr< \A \\ (?: [^\w\s] | # delimiters/metas [tnrfae] | # C-style escapes 0 [01234567]{0,2} | # octal # [01234567]{1,3} | # made from backref by lexer c [][\@[:alpha:]\\^_?] | # control characters x (?: \{ [[:xdigit:]]* \} | [[:xdigit:]]{0,2} ) | # hex o [{] [01234567]+ [}] | # octal as of 5.13.3 ## N (?: \{ (?: [[:alpha:]] [\w\s:()-]* | # must begin w/ alpha ## U [+] [[:xdigit:]]+ ) \} ) | # unicode N (?: [{] (?= \D ) [^\}]* [}] ) # unicode ) >smx ) ) { my $match = $tokenizer->match(); my $code; $code = $special{$match} and return $code->( $tokenizer, $accept ); return $accept; } return; } } =head2 ordinal print 'The ordinal of ', $token->content(), ' is ', $token->ordinal(), "\n"; This method returns the ordinal of the literal if it can figure it out. It is analogous to the C built-in. It will not attempt to determine the ordinal of a unicode name (C<\N{...}>) unless L has been loaded, and supports the L function. Instead, it will return C. Users of Perl 5.6.2 and older may be out of luck here. Unicode code points (e.g. C<\N{U+abcd}>) should work independently of L, and just return the value of C. It will never attempt to return the ordinal of an octet (C<\C{...}>) because I don't understand the syntax. =cut { my %escapes = ( '\\t' => ord "\t", '\\n' => ord "\n", '\\r' => ord "\r", '\\f' => ord "\f", '\\a' => ord "\a", '\\b' => ord "\b", '\\e' => ord "\e", '\\c?' => ord "\c?", '\\c@' => ord "\c@", '\\cA' => ord "\cA", '\\ca' => ord "\cA", '\\cB' => ord "\cB", '\\cb' => ord "\cB", '\\cC' => ord "\cC", '\\cc' => ord "\cC", '\\cD' => ord "\cD", '\\cd' => ord "\cD", '\\cE' => ord "\cE", '\\ce' => ord "\cE", '\\cF' => ord "\cF", '\\cf' => ord "\cF", '\\cG' => ord "\cG", '\\cg' => ord "\cG", '\\cH' => ord "\cH", '\\ch' => ord "\cH", '\\cI' => ord "\cI", '\\ci' => ord "\cI", '\\cJ' => ord "\cJ", '\\cj' => ord "\cJ", '\\cK' => ord "\cK", '\\ck' => ord "\cK", '\\cL' => ord "\cL", '\\cl' => ord "\cL", '\\cM' => ord "\cM", '\\cm' => ord "\cM", '\\cN' => ord "\cN", '\\cn' => ord "\cN", '\\cO' => ord "\cO", '\\co' => ord "\cO", '\\cP' => ord "\cP", '\\cp' => ord "\cP", '\\cQ' => ord "\cQ", '\\cq' => ord "\cQ", '\\cR' => ord "\cR", '\\cr' => ord "\cR", '\\cS' => ord "\cS", '\\cs' => ord "\cS", '\\cT' => ord "\cT", '\\ct' => ord "\cT", '\\cU' => ord "\cU", '\\cu' => ord "\cU", '\\cV' => ord "\cV", '\\cv' => ord "\cV", '\\cW' => ord "\cW", '\\cw' => ord "\cW", '\\cX' => ord "\cX", '\\cx' => ord "\cX", '\\cY' => ord "\cY", '\\cy' => ord "\cY", '\\cZ' => ord "\cZ", '\\cz' => ord "\cZ", '\\c[' => ord "\c[", '\\c\\\\' => ord "\c\\", # " # Get Vim's head straight. '\\c]' => ord "\c]", '\\c^' => ord "\c^", '\\c_' => ord "\c_", ); sub ordinal { my ( $self ) = @_; exists $self->{ordinal} and return $self->{ordinal}; return ( $self->{ordinal} = $self->_ordinal() ); } my %octal = map {; "$_" => 1 } ( 0 .. 7 ); sub _ordinal { my ( $self ) = @_; my $content = $self->content(); $content =~ m/ \A \\ /smx or return ord $content; exists $escapes{$content} and return $escapes{$content}; my $indicator = substr $content, 1, 1; $octal{$indicator} and return oct substr $content, 1; if ( $indicator eq 'x' ) { $content =~ m/ \A \\ x \{ ( [[:xdigit:]]+ ) \} \z /smx and return hex $1; $content =~ m/ \A \\ x ( [[:xdigit:]]{0,2} ) \z /smx and return hex $1; return; } if ( $indicator eq 'o' ) { $content =~ m/ \A \\ o [{] ( [01234567]+ ) [}] \z /smx and return oct $1; return; # Shouldn't happen, but ... } if ( $indicator eq 'N' ) { $content =~ m/ \A \\ N \{ U [+] ( [[:xdigit:]]+ ) \} \z /smx and return hex $1; $content =~ m/ \A \\ N [{] ( .+ ) [}] \z /smx and return ( _have_charnames_vianame() ? charnames::vianame( $1 ) : undef ); return; # Shouldn't happen, but ... } return ord $indicator; } } sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_REMOVED_PHASE_2; } { my $have_charnames_vianame; sub _have_charnames_vianame { defined $have_charnames_vianame and return $have_charnames_vianame; return ( $have_charnames_vianame = charnames->can( 'vianame' ) ? 1 : 0 ); } } sub __perl_requirements_setup { my ( $self ) = @_; my $prev; q<{> eq $self->content() # } and $prev = $self->sprevious_sibling() and $prev->isa( 'PPIx::Regexp::Token::Literal' ) or return $self->SUPER::__perl_requirements_setup(); return ( { introduced => MINIMUM_PERL, removed => LITERAL_LEFT_CURLY_REMOVED_PHASE_1, }, # TODO the following will be needed if this construction is # re-allowed in 5.26.1: # { # introduced => '5.026001', # removed => '6.027000', # }, { introduced => '5.027001', removed => LITERAL_LEFT_CURLY_REMOVED_PHASE_2, }, ); } *__PPIX_TOKENIZER__repl = \&__PPIX_TOKENIZER__regexp; 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Modifier.pm000444000765000024 3543313237102475 21043 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Modifier - Represent modifiers. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo}smx' ) ->print(); The trailing C will be represented by this class. This class also represents the whole of things like C<(?ismx)>. But the modifiers in something like C<(?i:foo)> are represented by a L. =head1 INHERITANCE C is a L. C is the parent of L. =head1 DESCRIPTION This class represents modifier characters at the end of the regular expression. For example, in C this class would represent the terminal C. =head2 The C, C, C, C, and C modifiers The C, C, C, C, and C modifiers, introduced starting in Perl 5.13.6, are used to force either Unicode pattern semantics (C), locale semantics (C) default semantics (C the traditional Perl semantics, which can also mean 'dual' since it means Unicode if the string's UTF-8 bit is on, and locale if the UTF-8 bit is off), or restricted default semantics (C). These are mutually exclusive, and only one can be asserted at a time. Asserting any of these overrides the inherited value of any of the others. The C method reports as asserted the last one it sees, or none of them if it has seen none. For example, given C C<$elem> representing the invalid regular expression fragment C<(?dul)>, C<< $elem->asserted( 'l' ) >> would return true, but C<< $elem->asserted( 'u' ) >> would return false. Note that C<< $elem->negated( 'u' ) >> would also return false, since C is not explicitly negated. If C<$elem> represented regular expression fragment C<(?i)>, C<< $elem->asserted( 'd' ) >> would return false, since even though C represents the default behavior it is not explicitly asserted. =head2 The caret (C<^>) modifier Calling C<^> a modifier is a bit of a misnomer. The C<(?^...)> construction was introduced in Perl 5.13.6, to prevent the inheritance of modifiers. The documentation calls the caret a shorthand equivalent for C, and that it the way this class handles it. For example, given C C<$elem> representing regular expression fragment C<(?^i)>, C<< $elem->asserted( 'd' ) >> would return true, since in the absence of an explicit C or C this class considers the C<^> to explicitly assert C. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::Modifier; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use Carp; use PPIx::Regexp::Constant qw{ MINIMUM_PERL MODIFIER_GROUP_MATCH_SEMANTICS }; our $VERSION = '0.055'; # Define modifiers that are to be aggregated internally for ease of # computation. my %aggregate = ( a => MODIFIER_GROUP_MATCH_SEMANTICS, aa => MODIFIER_GROUP_MATCH_SEMANTICS, d => MODIFIER_GROUP_MATCH_SEMANTICS, l => MODIFIER_GROUP_MATCH_SEMANTICS, u => MODIFIER_GROUP_MATCH_SEMANTICS, ); my %de_aggregate; foreach my $value ( values %aggregate ) { $de_aggregate{$value}++; } use constant TOKENIZER_ARGUMENT_REQUIRED => 1; sub __new { my ( $class, $content, %arg ) = @_; my $self = $class->SUPER::__new( $content, %arg ) or return; $arg{tokenizer}->modifier_modify( $self->modifiers() ); return $self; } =head2 asserts $token->asserts( 'i' ) and print "token asserts i"; foreach ( $token->asserts() ) { print "token asserts $_\n" } This method returns true if the token explicitly asserts the given modifier. The example would return true for the modifier in C<(?i:foo)>, but false for C<(?-i:foo)>. Starting with version 0.036_01, if the argument is a single-character modifier followed by an asterisk (intended as a wild card character), the return is the number of times that modifier appears. In this case an exception will be thrown if you specify a multi-character modifier (e.g. C<'ee*'>), or if you specify one of the match semantics modifiers (e.g. C<'a*'>). If called without an argument, or with an undef argument, all modifiers explicitly asserted by this token are returned. =cut sub asserts { my ( $self, $modifier ) = @_; $self->{modifiers} ||= $self->_decode(); if ( defined $modifier ) { return __asserts( $self->{modifiers}, $modifier ); } else { return ( sort grep { defined $_ && $self->{modifiers}{$_} } map { $de_aggregate{$_} ? $self->{modifiers}{$_} : $_ } keys %{ $self->{modifiers} } ); } } # This is a kluge for both determining whether the object asserts # modifiers (hence the 'ductype') and determining whether the given # modifier is actually asserted. The signature is the invocant and the # modifier name, which must not be undef. The return is a boolean. *__ducktype_modifier_asserted = \&asserts; sub __asserts { my ( $present, $modifier ) = @_; if ( my $bin = $aggregate{$modifier} ) { return defined $present->{$bin} && $modifier eq $present->{$bin}; } if ( $modifier =~ s/ [*] \z //smx ) { $aggregate{$modifier} and croak "Can not use wild card on modifier '$modifier*'"; 1 == length $modifier or croak "Can not use wild card on multi-character modifier '$modifier*'"; return $present->{$modifier} || 0; } my $len = length $modifier; $modifier = substr $modifier, 0, 1; return $present->{$modifier} && $len == $present->{$modifier}; } sub can_be_quantified { return }; { my %explanation = ( 'm' => 'm: ^ and $ match within string', '-m' => '-m: ^ and $ match only at ends of string', 's' => 's: . can match newline', '-s' => '-s: . can not match newline', 'i' => 'i: do case-insensitive matching', '-i' => '-i: do case-sensitive matching', 'x' => 'x: ignore whitespace and comments', 'xx' => 'xx: ignore whitespace even in bracketed character classes', '-x' => '-x: regard whitespace as literal', 'p' => 'p: provide ${^PREMATCH} etc (pre 5.20)', '-p' => '-p: no ${^PREMATCH} etc (pre 5.20)', 'a' => 'a: restrict non-Unicode classes to ASCII', 'aa' => 'aa: restrict non-Unicode classes & ASCII-Unicode matches', 'd' => 'd: match using default semantics', 'l' => 'l: match using locale semantics', 'u' => 'u: match using Unicode semantics', 'n' => 'n: parentheses do not capture', '-n' => '-n: parentheses capture', 'c' => 'c: preserve current position on match failure', 'g' => 'g: match repeatedly', 'e' => 'e: substitution string is an expression', 'ee' => 'ee: substitution is expression to eval()', 'o' => 'o: only interpolate once', 'r' => 'r: aubstitution returns modified string', ); sub explain { my ( $self ) = @_; my @rslt; my %mods = $self->modifiers(); if ( defined( my $val = delete $mods{match_semantics} ) ) { push @rslt, $explanation{$val}; } foreach my $key ( sort keys %mods ) { if ( my $val = $mods{$key} ) { push @rslt, $explanation{ $key x $val }; } else { push @rslt, $explanation{ "-$key" }; } } return wantarray ? @rslt : join '; ', @rslt; } } =head2 match_semantics my $sem = $token->match_semantics(); defined $sem or $sem = 'undefined'; print "This token has $sem match semantics\n"; This method returns the match semantics asserted by the token, as one of the strings C<'a'>, C<'aa'>, C<'d'>, C<'l'>, or C<'u'>. If no explicit match semantics are asserted, this method returns C. =cut sub match_semantics { my ( $self ) = @_; $self->{modifiers} ||= $self->_decode(); return $self->{modifiers}{ MODIFIER_GROUP_MATCH_SEMANTICS() }; } =head2 modifiers my %mods = $token->modifiers(); Returns all modifiers asserted or negated by this token, and the values set (true for asserted, false for negated). If called in scalar context, returns a reference to a hash containing the values. =cut sub modifiers { my ( $self ) = @_; $self->{modifiers} ||= $self->_decode(); my %mods = %{ $self->{modifiers} }; foreach my $bin ( keys %de_aggregate ) { defined ( my $val = delete $mods{$bin} ) or next; $mods{$bin} = $val; } return wantarray ? %mods : \%mods; } =head2 negates $token->negates( 'i' ) and print "token negates i\n"; foreach ( $token->negates() ) { print "token negates $_\n" } This method returns true if the token explicitly negates the given modifier. The example would return true for the modifier in C<(?-i:foo)>, but false for C<(?i:foo)>. If called without an argument, or with an undef argument, all modifiers explicitly negated by this token are returned. =cut sub negates { my ( $self, $modifier ) = @_; $self->{modifiers} ||= $self->_decode(); # Note that since the values of hash entries that represent # aggregated modifiers will never be false (at least, not unless '0' # becomes a modifier) we need no special logic to handle them. defined $modifier or return ( sort grep { ! $self->{modifiers}{$_} } keys %{ $self->{modifiers} } ); return exists $self->{modifiers}{$modifier} && ! $self->{modifiers}{$modifier}; } sub perl_version_introduced { my ( $self ) = @_; return ( $self->{perl_version_introduced} ||= $self->_perl_version_introduced() ); } sub _perl_version_introduced { my ( $self ) = @_; my $content = $self->content(); my $is_statement_modifier = ( $content !~ m/ \A [(]? [?] /smx ); my $match_semantics = $self->match_semantics(); $self->asserts( 'xx' ) and return '5.025009'; # Disabling capture with /n was introduced in 5.21.8 $self->asserts( 'n' ) and return '5.021008'; # Match semantics modifiers became available as regular expression # modifiers in 5.13.10. defined $match_semantics and $is_statement_modifier and return '5.013010'; # /aa was introduced in 5.13.10. defined $match_semantics and 'aa' eq $match_semantics and return '5.013010'; # /a was introduced in 5.13.9, but only in (?...), not as modifier # of the entire regular expression. defined $match_semantics and not $is_statement_modifier and 'a' eq $match_semantics and return '5.013009'; # /d, /l, and /u were introduced in 5.13.6, but only in (?...), not # as modifiers of the entire regular expression. defined $match_semantics and not $is_statement_modifier and return '5.013006'; # The '^' reassert-defaults modifier in embedded modifiers was # introduced in 5.13.6. not $is_statement_modifier and $content =~ m/ \^ /smx and return '5.013006'; $self->asserts( 'r' ) and return '5.013002'; $self->asserts( 'p' ) and return '5.009005'; $self->content() =~ m/ \A [(]? [?] .* - /smx and return '5.005'; $self->asserts( 'c' ) and return '5.004'; return MINIMUM_PERL; } # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; # $present => __aggregate_modifiers( 'modifiers', ... ); # # This subroutine is private to the PPIx::Regexp package. It may change # or be retracted without notice. Its purpose is to support defaulted # modifiers. # # Aggregate the given modifiers left-to-right, returning a hash of those # present and their values. sub __aggregate_modifiers { my ( @mods ) = @_; my %present; foreach my $content ( @mods ) { $content =~ s{ [?/]+ }{}smxg; if ( $content =~ m/ \A \^ /smx ) { @present{ MODIFIER_GROUP_MATCH_SEMANTICS(), qw{ i s m x } } = qw{ d 0 0 0 0 }; } # Have to do the global match rather than a split, because the # expression modifiers come through here too, and we need to # distinguish between s/.../.../e and s/.../.../ee. But the # modifiers can be randomized (that is, /eie is the same as # /eei), so we reorder the content first. # The following line is WRONG because it ignores the # significance of '-'. This bug was introduced in version 0.035, # specifically by the change that handled multi-character # modifiers. # $content = join '', sort split qr{}smx, $content; # The following is better because it re-orders the modifiers # separately. It does not recognize multiple dashes as # representing an error (though it could!), and modifiers that # are both asserted and negated (e.g. '(?i-i:foo)') are simply # considered to be negated (as Perl does as of 5.20.0). $content = join '-', map { join '', sort split qr{}smx } split qr{-}smx, $content; my $value = 1; while ( $content =~ m/ ( ( [[:alpha:]-] ) \2* ) /smxg ) { if ( '-' eq $1 ) { $value = 0; } elsif ( my $bin = $aggregate{$1} ) { # Yes, technically the match semantics stuff can't be # negated in a regex. But it can in a 'use re', which # also comes through here, so we have to handle it. $present{$bin} = $value ? $1 : undef; } else { # TODO have to think about this, since I need asserts( # 'e' ) to be 2 if we in fact have 'ee'. Is this # correct? # $present{$1} = $value; $present{$2} = $value * length $1; } } } return \%present; } # This must be implemented by tokens which do not recognize themselves. # The return is a list of list references. Each list reference must # contain a regular expression that recognizes the token, and optionally # a reference to a hash to pass to make_token as the class-specific # arguments. The regular expression MUST be anchored to the beginning of # the string. sub __PPIX_TOKEN__recognize { return ( [ qr{ \A [(] [?] [[:lower:]]* -? [[:lower:]]* [)] }smx ], [ qr{ \A [(] [?] \^ [[:lower:]]* [)] }smx ], ); } { # Called by the tokenizer to modify the current modifiers with a new # set. Both are passed as hash references, and a reference to the # new hash is returned. sub __PPIX_TOKENIZER__modifier_modify { my ( @args ) = @_; my %merged; foreach my $hash ( @args ) { while ( my ( $key, $val ) = each %{ $hash } ) { if ( $val ) { $merged{$key} = $val; } else { delete $merged{$key}; } } } return \%merged; } # Decode modifiers from the content of the token. sub _decode { my ( $self ) = @_; return __aggregate_modifiers( $self->content() ); } } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/NoOp.pm000444000765000024 370513237102475 20135 0ustar00tomstaff000000000000package PPIx::Regexp::Token::NoOp; use 5.006; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use Carp; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; our $VERSION = '0.055'; { my %when_removed = ( '\\N{}' => '5.027001', ); sub __new { my ( $class, $content, %arg ) = @_; defined $arg{perl_version_introduced} or $arg{perl_version_introduced} = MINIMUM_PERL; exists $arg{perl_version_removed} or $arg{perl_version_removed} = $when_removed{$content}; return $class->SUPER::__new( $content, %arg ); } } # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; sub explain { return 'Not significant'; } sub significant { return; } 1; __END__ =head1 NAME PPIx::Regexp::Token::NoOp - Represent a token that does nothing. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr< \N{} >smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L. =head1 DESCRIPTION This class represents a token the does nothing. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2016-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Operator.pm000444000765000024 1163513237102475 21076 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Operator - Represent an operator. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo|bar}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents an operator. In a character class, it represents the negation (C<^>) and range (C<->) operators. Outside a character class, it represents the alternation (C<|>) operator. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Operator; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPIx::Regexp::Constant qw{ COOKIE_CLASS COOKIE_REGEX_SET LITERAL_LEFT_CURLY_ALLOWED TOKEN_LITERAL }; use PPIx::Regexp::Util qw{ __instance }; our $VERSION = '0.055'; use constant TOKENIZER_ARGUMENT_REQUIRED => 1; sub __new { my ( $class, $content, %arg ) = @_; my $self = $class->SUPER::__new( $content, %arg ) or return; $self->{operation} = $self->_compute_operation_name( $arg{tokenizer} ) || 'unknown'; return $self; } # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub explain { my ( $self ) = @_; my $expl = ucfirst "$self->{operation} operator"; $expl =~ s/ _ / /smxg; return $expl; } =head2 operation This method returns the name of the operation performed by the operator. This depends not only on the operator itself but its context: =over =item In a bracketed character class '-' => 'range', '^' => 'inversion', =item In an extended bracketed character class '&' => 'intersection', '+' => 'union', '|' => 'union', '-' => 'subtraction', '^' => 'symmetric_difference', '!' => 'complement', =item Outside any sort of bracketed character class '|' => 'alternation', =back =cut sub operation { my ( $self ) = @_; return $self->{operation}; } # These will be intercepted by PPIx::Regexp::Token::Literal if they are # really literals, so here we may process them unconditionally. # Note that if we receive a '-' we unconditionally make it an operator, # relying on the lexer to turn it back into a literal if necessary. my %operator = map { $_ => 1 } qw{ | - }; sub _treat_as_literal { my ( $token ) = @_; return __instance( $token, 'PPIx::Regexp::Token::Literal' ) || __instance( $token, 'PPIx::Regexp::Token::Interpolation' ); } { my %operation = ( COOKIE_CLASS() => { '-' => 'range', '^' => 'inversion', }, COOKIE_REGEX_SET() => { '&' => 'intersection', '+' => 'union', '|' => 'union', '-' => 'subtraction', '^' => 'symmetric_difference', '!' => 'complement', }, '' => { '|' => 'alternation', }, ); sub _compute_operation_name { my ( $self, $tokenizer ) = @_; my $content = $self->content(); if ( $tokenizer->cookie( COOKIE_CLASS ) ) { return $operation{ COOKIE_CLASS() }{$content}; } elsif ( $tokenizer->cookie( COOKIE_REGEX_SET ) ) { return $operation{ COOKIE_REGEX_SET() }{$content}; } else { return $operation{''}{$content}; } } } { my $removed_in = { '|' => LITERAL_LEFT_CURLY_ALLOWED, # Allowed after alternation }; sub __following_literal_left_curly_disallowed_in { my ( $self ) = @_; my $content = $self->content(); exists $removed_in->{$content} and return $removed_in->{$content}; return $self->SUPER::__following_literal_left_curly_disallowed_in(); } } sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; # We only receive the '-' if we are inside a character class. But it # is only an operator if it is preceded and followed by literals. We # can use prior() because there are no insignificant tokens inside a # character class. if ( $character eq '-' ) { _treat_as_literal( $tokenizer->prior_significant_token() ) or return $tokenizer->make_token( 1, TOKEN_LITERAL ); my @tokens = ( $tokenizer->make_token( 1 ) ); push @tokens, $tokenizer->get_token(); _treat_as_literal( $tokens[1] ) or bless $tokens[0], TOKEN_LITERAL; return ( @tokens ); } return $operator{$character}; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Quantifier.pm000444000765000024 503313237102475 21365 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Quantifier - Represent an atomic quantifier. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{\w+}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents an atomic quantifier; that is, one of the characters C<*>, C<+>, or C. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::Quantifier; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPIx::Regexp::Constant qw{ LITERAL_LEFT_CURLY_ALLOWED }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; # Return true if the token is a quantifier. sub is_quantifier { return 1 }; my %quantifier = map { $_ => 1 } qw{ * + ? }; =head2 could_be_quantifier PPIx::Regexp::Token::Quantifier->could_be_quantifier( '*' ); This method returns true if the given string could be a quantifier; that is, if it is '*', '+', or '?'. =cut sub could_be_quantifier { my ( undef, $string ) = @_; # Invocant unused return $quantifier{$string}; } { my %explanation = ( '*' => 'match zero or more times', '+' => 'match one or more times', '?' => 'match zero or one time', ); sub __explanation { return \%explanation; } } sub __following_literal_left_curly_disallowed_in { return LITERAL_LEFT_CURLY_ALLOWED; } sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; $tokenizer->prior_significant_token( 'can_be_quantified' ) or return; return $quantifier{$character}; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Recursion.pm000444000765000024 567713237102475 21245 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Recursion - Represent a recursion =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(foo(?1)?)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a recursion to a named or numbered capture. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Recursion; use strict; use warnings; use base qw{ PPIx::Regexp::Token::Reference }; use Carp qw{ confess }; use PPIx::Regexp::Constant qw{ RE_CAPTURE_NAME }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub explain { my ( $self ) = @_; $self->is_named() and return sprintf q, $self->name(); if ( $self->is_relative() ) { my $number = $self->number(); $number >= 0 and return sprintf q, PPIx::Regexp::Util::__to_ordinal_en( $self->number() ), $self->absolute(); return sprintf q, PPIx::Regexp::Util::__to_ordinal_en( - $self->number() ), $self->absolute(); } elsif ( my $number = $self->absolute() ) { return sprintf q, $number; } else { return q; } } sub perl_version_introduced { return '5.009005'; } # This must be implemented by tokens which do not recognize themselves. # The return is a list of list references. Each list reference must # contain a regular expression that recognizes the token, and optionally # a reference to a hash to pass to make_token as the class-specific # arguments. The regular expression MUST be anchored to the beginning of # the string. sub __PPIX_TOKEN__recognize { return ( [ qr{ \A \( \? (?: ( [-+]? \d+ )) \) }smx, { is_named => 0 } ], [ qr{ \A \( \? (?: R) \) }smx, { is_named => 0, capture => '0' } ], [ qr{ \A \( \? (?: & | P> ) ( @{[ RE_CAPTURE_NAME ]} ) \) }smxo, { is_named => 1 } ], ); } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Reference.pm000444000765000024 1135713237102475 21202 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Reference - Represent a reference to a capture =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{\1}smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L, L and L. =head1 DESCRIPTION This abstract class represents a reference to a capture buffer, either numbered or named. It should never be instantiated, but it provides a number of methods to its subclasses. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::Reference; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use Carp qw{ confess }; use List::Util qw{ first }; our $VERSION = '0.055'; sub __new { my ( $class, $content, %arg ) = @_; if ( defined $arg{capture} ) { } elsif ( defined $arg{tokenizer} ) { $arg{capture} = first { defined $_ } $arg{tokenizer}->capture(); } unless ( defined $arg{capture} ) { foreach ( $class->__PPIX_TOKEN__recognize() ) { my ( $re, $a ) = @{ $_ }; $content =~ $re or next; @arg{ keys %{ $a } } = @{ $a }{ keys %{ $a } }; foreach my $inx ( 1 .. $#- ) { defined $-[$inx] or next; $arg{capture} = substr $content, $-[$inx], $+[$inx] - $-[$inx]; last; } last; } } defined $arg{capture} or confess q{Programming error - reference '}, $content, q{' of unknown form}; my $self = $class->SUPER::__new( $content, %arg ) or return; $self->{is_named} = $arg{is_named}; my $capture = delete $arg{capture}; if ( $self->{is_named} ) { $self->{absolute} = undef; $self->{is_relative} = undef; $self->{name} = $capture; } elsif ( $capture !~ m/ \A [-+] /smx ) { $self->{absolute} = $self->{number} = $capture; $self->{is_relative} = undef; } else { $self->{number} = $capture; $self->{is_relative} = 1; } return $self; } =head2 absolute print "The absolute reference is ", $ref->absolute(), "\n"; This method returns the absolute number of the capture buffer referred to. This is the same as number() for unsigned numeric references. If the reference is to a named buffer, C is returned. =cut sub absolute { my ( $self ) = @_; return $self->{absolute}; } =head2 is_named $ref->is_named and print "named reference\n"; This method returns true if the reference is named rather than numbered. =cut sub is_named { my ( $self ) = @_; return $self->{is_named}; } =head2 is_relative $ref->is_relative() and print "relative numbered reference\n"; This method returns true if the reference is numbered and it is a relative number (i.e. if it is signed). =cut sub is_relative { my ( $self ) = @_; return $self->{is_relative}; } =head2 name print "The name is ", $ref->name(), "\n"; This method returns the name of the capture buffer referred to. In the case of a reference to a numbered capture (i.e. C returns false), this method returns C. =cut sub name { my ( $self ) = @_; return $self->{name}; } =head2 number print "The number is ", $ref->number(), "\n"; This method returns the number of the capture buffer referred to. In the case of a reference to a named capture (i.e. C returns true), this method returns C. =cut sub number { my ( $self ) = @_; return $self->{number}; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( $self, $number ) = @_; if ( ! exists $self->{absolute} && exists $self->{number} && $self->{number} =~ m/ \A [-+] /smx ) { my $delta = $self->{number}; $delta > 0 and --$delta; # no -0 or +0. $self->{absolute} = $number + $delta; } return $number; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Structure.pm000444000765000024 2466313237102475 21310 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Structure - Represent structural elements. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(foo)}smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L. =head1 DESCRIPTION This class represents things that define the structure of the regular expression. This typically means brackets of various sorts, but to prevent proliferation of token classes the type of the regular expression is stored here. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Structure; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use PPIx::Regexp::Constant qw{ COOKIE_CLASS COOKIE_QUANT COOKIE_REGEX_SET MINIMUM_PERL TOKEN_LITERAL }; # Tokens we are responsible for making, under at least some # circumstances. use PPIx::Regexp::Token::Comment (); use PPIx::Regexp::Token::Modifier (); use PPIx::Regexp::Token::Backreference (); use PPIx::Regexp::Token::Backtrack (); use PPIx::Regexp::Token::Recursion (); our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise my %quant = map { $_ => 1 } ')', ']'; sub can_be_quantified { my ( $self ) = @_; ref $self or return; return $quant{ $self->content() }; }; { my %explanation = ( '' => 'Match regexp', '(' => 'Capture or grouping', '(?[' => 'Extended character class', ')' => 'End capture or grouping', '[' => 'Character class', ']' => 'End character class', '])' => 'End extended character class', 'm' => 'Match regexp', 'qr' => 'Regexp object definition', 's' => 'Replace regexp with string or expression', '{' => 'Explicit quantifier', '}' => 'End explicit quantifier', ); sub __explanation { return \%explanation; } } sub is_quantifier { my ( $self ) = @_; ref $self or return; return $self->{is_quantifier}; } { # Note that the implementation equivocates on the ::Token::Structure # class, using it both for the initial token that determines the # type of the regex and things like parentheses internal to the # regex. Rather than sort out this equivocation, I have relied on # the currently-true assumption that 'qr' will not satisfy the # ::Token::Structure recognition logic, and the only way this class # can acquire this content is by the brute-force approach used to # generate the initial token object. my %perl_version_introduced = ( qr => '5.005', '(?[' => '5.017008', ); sub perl_version_introduced { my ( $self ) = @_; return $perl_version_introduced{ $self->content() } || MINIMUM_PERL; } } { my %delim = map { $_ => 1 } qw/ ( ) { } [ ] /; # Regular expressions to match various parenthesized tokens, and the # classes to make them into. my @paren_token = map { [ $_ => $_->__PPIX_TOKEN__recognize() ] } 'PPIx::Regexp::Token::Comment', 'PPIx::Regexp::Token::Modifier', 'PPIx::Regexp::Token::Backreference', 'PPIx::Regexp::Token::Backtrack', 'PPIx::Regexp::Token::Recursion', ; sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; # We are not interested in anything but delimiters. $delim{$character} or return; # Inside a character class, all the delimiters are normal characters # except for the close square bracket. if ( $tokenizer->cookie( COOKIE_CLASS ) ) { $character eq ']' or return $tokenizer->make_token( 1, TOKEN_LITERAL ); $tokenizer->cookie( COOKIE_CLASS, undef ); return 1; } # Open parentheses have various interesting possibilities ... if ( $character eq '(' ) { # Sometimes the whole bunch of parenthesized characters seems # naturally to be a token. foreach ( @paren_token ) { my ( $class, @recognize ) = @{ $_ }; foreach ( @recognize ) { my ( $regexp, $arg ) = @{ $_ }; my $accept = $tokenizer->find_regexp( $regexp ) or next; return $tokenizer->make_token( $accept, $class, $arg ); } } # Modifier changes are local to this parenthesis group $tokenizer->modifier_duplicate(); # The regex-set functionality introduced with 5.17.8 is most # conveniently handled by treating the initial '(?[' and # final '])' as ::Structure tokens. Fortunately for us, # perl5178delta documents that these may not have interior # spaces. if ( my $accept = $tokenizer->find_regexp( qr{ \A [(] [?] [[] }smx # ] ) - help for vim ) ) { $tokenizer->cookie( COOKIE_REGEX_SET, sub { return 1 } ); $tokenizer->modifier_modify( x => 1 ); # Implicitly /x return $accept; } # We expect certain tokens only after a left paren. $tokenizer->expect( 'PPIx::Regexp::Token::GroupType::Modifier', 'PPIx::Regexp::Token::GroupType::NamedCapture', 'PPIx::Regexp::Token::GroupType::Assertion', 'PPIx::Regexp::Token::GroupType::Code', 'PPIx::Regexp::Token::GroupType::BranchReset', 'PPIx::Regexp::Token::GroupType::Subexpression', 'PPIx::Regexp::Token::GroupType::Switch', 'PPIx::Regexp::Token::GroupType::Script_Run', ); # Accept the parenthesis. return 1; } # Close parentheses end modifier localization if ( $character eq ')' ) { $tokenizer->modifier_pop(); return 1; } # Open curlys are complicated because they may or may not represent # the beginning of a quantifier, depending on what comes before the # close curly. So we set a cookie to monitor the token stream for # interlopers. If all goes well, the right curly will find the # cookie and know it is supposed to be a quantifier. if ( $character eq '{' ) { # If the prior token can not be quantified, all this is # unnecessary. $tokenizer->prior_significant_token( 'can_be_quantified' ) or return 1; # We make our token now, before setting the cookie. Otherwise # the cookie has to deal with this token. my $token = $tokenizer->make_token( 1 ); # A cookie for the next '}'. my $commas = 0; $tokenizer->cookie( COOKIE_QUANT, sub { my ( $tokenizer, $token ) = @_; $token or return 1; # Of literals, we accept exactly one comma provided it # is not immediately after a '{'. We also accept # anything that matches '\d'; if ( $token->isa( TOKEN_LITERAL ) ) { my $character = $token->content(); if ( $character eq ',' ) { $commas++ and return; return $tokenizer->prior_significant_token( 'content' ) ne '{'; } return $character =~ m/ \A \d \z /smx; } # Since we do not know what is in an interpolation, we # trustingly accept it. if ( $token->isa( 'PPIx::Regexp::Token::Interpolation' ) ) { return 1; } return; }, ); return $token; } # The close curly bracket is a little complicated because if the # cookie posted by the left curly bracket is still around, we are a # quantifier, otherwise not. if ( $character eq '}' ) { $tokenizer->cookie( COOKIE_QUANT, undef ) or return 1; $tokenizer->prior_significant_token( 'class' )->isa( __PACKAGE__ ) and return 1; my $token = $tokenizer->make_token( 1 ); $token->{is_quantifier} = 1; return $token; } # The parse rules are different inside a character class, so we set # another cookie. Sigh. If your tool is a hammer ... if ( $character eq '[' ) { # Set our cookie. Since it always returns 1, it does not matter # where in the following mess we set it. $tokenizer->cookie( COOKIE_CLASS, sub { return 1 } ); # Make our token now, since the easiest place to deal with the # beginning-of-character-class strangeness seems to be right # here. my @tokens = $tokenizer->make_token( 1 ); # Get the next character, returning tokens if there is none. defined ( $character = $tokenizer->peek() ) or return @tokens; # If we have a caret, it is a negation operator. Make its token # and fetch the next character, returning if none. if ( $character eq '^' ) { push @tokens, $tokenizer->make_token( 1, 'PPIx::Regexp::Token::Operator' ); defined ( $character = $tokenizer->peek() ) or return @tokens; } # If we have a close square at this point, it is not the end of # the class, but just a literal. Make its token. $character eq ']' and push @tokens, $tokenizer->make_token( 1, TOKEN_LITERAL ); # Return all tokens made. return @tokens; } # per perlop, the metas inside a [] are -]\^$. # per perlop, the metas outside a [] are {}[]()^$.|*+?\ # The difference is that {}[().|*+? are not metas in [], but - is. # Close bracket is complicated by the addition of regex sets. # And more complicated by the fact that you can have an # old-style character class inside a regex set. Fortunately they # have not (yet!) permitted nested regex sets. if ( $character eq ']' ) { # If we find '])' and COOKIE_REGEX_SET is present, we have a # regex set. We need to delete the cookie and accept both # characters. if ( ( my $accept = $tokenizer->find_regexp( # help vim - ( [ qr{ \A []] [)] }smx ) ) && $tokenizer->cookie( COOKIE_REGEX_SET ) ) { $tokenizer->cookie( COOKIE_REGEX_SET, undef ); return $accept; } # Otherwise we assume we're in a bracketed character class, # delete the cookie, and accept the close bracket. $tokenizer->cookie( COOKIE_CLASS, undef ); return 1; } return 1; } } # Called by the lexer once it has done its worst to all the tokens. # Called as a method with no arguments. The return is the number of # parse failures discovered when finalizing. sub __PPIX_LEXER__finalize { my ( $self ) = @_; delete $self->{is_quantifier}; return 0; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Unknown.pm000444000765000024 552613237102475 20724 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Unknown - Represent an unknown token =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'xyzzy' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This token represents something that could not be identified by the tokenizer. Sometimes the lexer can fix these up, but the presence of one of these in a finished parse represents something in the regular expression that was not understood. =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::Unknown; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; use Carp qw{ confess }; our $VERSION = '0.055'; sub __new { my ( $class, $content, %arg ) = @_; defined $arg{error} or confess 'Programming error - error argument required'; my $self = $class->SUPER::__new( $content, %arg ) or return; $self->{error} = $arg{error}; return $self; } # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; =head2 ordinal This method returns the results of the ord built-in on the content (meaning, of course, the first character of the content). No attempt is made to interpret the content, since after all this B the unknown token. =cut sub ordinal { my ( $self ) = @_; return ord $self->content(); } sub __PPIX_ELEM__rebless { my ( $class, $self, %arg ) = @_; my $rslt = $class->SUPER::__PPIX_ELEM__rebless( $self, %arg ); unless ( defined( $self->{error} = $arg{error} ) ) { Carp::cluck( 'Making unknown token with no error message' ); $self->{error} = 'Unspecified error'; $rslt++; } return $rslt; } # Since the lexer does not count these on the way in (because it needs # the liberty to rebless them into a known class if it figures out what # is going on) we count them as failures at the finalization step. sub __PPIX_LEXER__finalize { return 1; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Unmatched.pm000444000765000024 332313237102475 21166 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Unmatched - Represent an unmatched right bracket =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class is used to represent an unmatched right bracket of any sort - parenthesis, square bracket, curly bracket, or whatever. This class is not generated by the tokenizer; instead the lexer reblesses a L into it when it is found to be unmatched. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Unmatched; use strict; use warnings; use base qw{ PPIx::Regexp::Token }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub explain { return 'Unmatched token'; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/Whitespace.pm000444000765000024 550313237102475 21354 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::Whitespace - Represent whitespace =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{ foo }smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents whitespace. It will appear inside the regular expression only if the C modifier is present, but it may also appear between the type and the opening delimiter (e.g. C) or after the regular expression in a bracketed substitution (e.g. C). If the C modifier is present, it can also appear inside bracketed character classes. This was introduced in Perl 5.25.9. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::Whitespace; use strict; use warnings; use base qw{ PPIx::Regexp::Token::NoOp }; use PPIx::Regexp::Constant qw{ COOKIE_REGEX_SET MINIMUM_PERL }; our $VERSION = '0.055'; sub __new { my ( $class, $content, %arg ) = @_; defined $arg{perl_version_introduced} or $arg{perl_version_introduced} = ( grep { 127 < ord } split qr{}, $content ) ? '5.021001' : MINIMUM_PERL; return $class->SUPER::__new( $content, %arg ); } sub explain { my ( $self ) = @_; my $parent; if ( $parent = $self->parent() and $parent->isa( 'PPIx::Regexp' ) ) { return $self->SUPER::explain(); } elsif ( $self->in_regex_set() ) { return q; } elsif ( my $count = $self->modifier_asserted( 'x*' ) ) { return q . ( 'x' x $count ); } else { return $self->SUPER::explain(); } } sub whitespace { return 1; } # Objects of this class are generated either by the tokenizer itself # (when scanning for delimiters) or by PPIx::Regexp::Token::Literal (if # it hits a match for \s and finds the regular expression has the /x # modifier asserted. # # sub __PPIX_TOKENIZER__regexp { # my ( $class, $tokenizer, $character ) = @_; # # return scalar $tokenizer->find_regexp( qr{ \A \s+ }smx ); # # } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/CharClass000755000765000024 013237102475 20425 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/CharClass/POSIX.pm000444000765000024 767713237102475 22043 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::CharClass::POSIX - Represent a POSIX character class =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{ [[:alpha:]] }smx' ) ->print(); =head1 INHERITANCE C is a L. C is the parent of L. =head1 DESCRIPTION This class represents a POSIX character class. It will only be recognized within a character class. Note that collating symbols (e.g. C<[.ch.]>) and equivalence classes (e.g. C<[=a=]>) are valid in the POSIX standard, but are not valid in Perl regular expressions. These end up being represented by L, and are considered a parse failure. =head1 METHODS This class provides the following public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::CharClass::POSIX; use strict; use warnings; use base qw{ PPIx::Regexp::Token::CharClass }; use PPIx::Regexp::Constant qw{ COOKIE_CLASS COOKIE_REGEX_SET MINIMUM_PERL }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; ##=head2 is_case_sensitive ## ##This override of the superclass method of the same name returns true if ##the character class is C<[:lower:]> or C<[:upper:]>, and false (but ##defined) for all other POSIX character classes. ## ##=cut ## ##{ ## my %case_sensitive = map { $_ => 1 } qw{ [:lower:] [:upper:] }; ## ## sub is_case_sensitive { ## my ( $self ) = @_; ## return $case_sensitive{ $self->content() } || 0; ## } ##} sub perl_version_introduced { # my ( $self ) = @_; return '5.006'; } { my %explanation = ( '[:alnum:]' => 'Any alphanumeric character', '[:alpha:]' => 'Match alphabetic', '[:ascii:]' => 'Any character in the ASCII character set', '[:blank:]' => 'A GNU extension, equal to a space or a horizontal tab ("\\t")', '[:cntrl:]' => 'Any control character', '[:digit:]' => 'Any decimal digit ("[0-9]")', '[:graph:]' => 'Any printable character, excluding a space', '[:lower:]' => 'Any lowercase character', '[:print:]' => 'Any printable character', '[:punct:]' => 'Any graphical character excluding "word" characters', '[:space:]' => 'Any whitespace character', '[:upper:]' => 'Any uppercase character', '[:word:]' => 'A Perl extension, equivalent to "\\w"', '[:xdigit:]' => 'Any hexadecimal digit', ); sub __explanation { return \%explanation; } sub __no_explanation { ## my ( $self ) = @_; # Invocant unused my $msg = sprintf q; return $msg; } } { my %class = ( ':' => __PACKAGE__, ); sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer ) = @_; # Invocant, $character unused $tokenizer->cookie( COOKIE_CLASS ) or $tokenizer->cookie( COOKIE_REGEX_SET ) or return; if ( my $accept = $tokenizer->find_regexp( qr{ \A [[] ( [.=:] ) \^? .*? \1 []] }smx ) ) { my ( $punc ) = $tokenizer->capture(); return $tokenizer->make_token( $accept, $class{$punc} || __PACKAGE__ . '::Unknown' ); } return; } } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/CharClass/Simple.pm000444000765000024 1654113237102475 22400 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::CharClass::Simple - This class represents a simple character class =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{\w}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents one of the simple character classes that can occur anywhere in a regular expression. This includes not only the truly simple things like \w, but also Unicode properties. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::CharClass::Simple; use strict; use warnings; use base qw{ PPIx::Regexp::Token::CharClass }; use PPIx::Regexp::Constant qw{ COOKIE_CLASS LITERAL_LEFT_CURLY_REMOVED_PHASE_1 LITERAL_LEFT_CURLY_REMOVED_PHASE_2 MINIMUM_PERL TOKEN_LITERAL TOKEN_UNKNOWN }; our $VERSION = '0.055'; { my %kind_of_match = ( p => 'with', P => 'without', ); my %explanation = ( '.' => 'Match any character', '\\C' => 'Match a single octet (removed in 5.23.0)', '\\D' => 'Match any character but a decimal digit', '\\H' => 'Match a non-horizontal-white-space character', '\\N' => 'Match any character but a new-line character', '\\R' => 'Match a generic new-line character', '\\S' => 'Match non-white-space character', '\\V' => 'Match a non-vertical-white-space character', '\\W' => 'Match non-word character', '\\X' => 'Match a Unicode extended grapheme cluster', '\\d' => 'Match decimal digit', '\\h' => 'Match a horizontal-white-space character', '\\s' => 'Match white-space character', '\\v' => 'Match a vertical-white-space character', '\\w' => 'Match word character', ); sub __explanation { return \%explanation; } sub explain { my ( $self ) = @_; if ( $self->content() =~ m/ \A \\ ( [Pp] ) ( [{] .* [}] | . ) \z /smx ) { my ( $kind, $prop ) = ( $1, $2 ); if ( 1 < length $prop ) { $prop =~ s/ \A [{] //smx; $prop =~ s/ [}] \z //smx; } return sprintf q, $kind_of_match{$kind}, $prop; } return $self->SUPER::explain(); } } ##=head2 is_case_sensitive ## ##This override of the superclass method returns true for Unicode ##properties that specify case, and false (but defined) for all ##other character classes. ## ##The classes that specify case are documented in ##L. ## ##B This method returns false (but defined) for user-defined ##Unicode properties. It should return C. This bug B be fixed ##if I find a way to identify all system-defined Unicode properties. ## ##=cut ## ##sub is_case_sensitive { ## my ( $self ) = @_; ## exists $self->{is_case_sensitive} ## and return $self->{is_case_sensitive}; ## return ( $self->{is_case_sensitive} = $self->_is_case_sensitive() ); ##} ##{ ## my %case_sensitive = map { $_ => 1 } qw{ ## generalcategory=lowercaseletter generalcategory=ll ## gc=lowercaseletter gc=ll ## generalcategory=titlecaseletter generalcategory=lt ## gc=titlecaseletter gc=lt ## generalcategory=uppercaseletter generalcategory=lu ## gc=uppercaseletter gc=lu ## lowercaseletter lowercase lower ll ## titlecaseletter titlecase title lt ## uppercaseletter uppercase upper lu ## lowercase=y lower=y lowercase=n lower=n ## titlecase=y title=y titlecase=n title=n ## uppercase=y upper=y uppercase=n upper=n ## }; ## ## sub _is_case_sensitive { ## my ( $self ) = @_; ## my $content = $self->content(); ## $content =~ m/ \A \\ p [{] ( .* ) [}] /smxi ## or return 0; ## $content = lc $1; ## $content =~ s/ \A ^ //smx; ## $content =~ s/ [\s_-] //smxg; ## $content =~ s/ \A is //smx; ## $content =~ s/ : /=/smxg; ## $content =~ s/ = (?: yes | t | true ) \b /=y/smxg; ## $content =~ s/ = (?: no | f | false ) \b /=n/smxg; ## return $case_sensitive{$content} || 0; ## } ## ##} { my %introduced = ( '\\h' => '5.009005', # Before this, parsed as 'h' '\\v' => '5.009005', # Before this, parsed as 'v' '\\H' => '5.009005', # Before this, parsed as 'H' '\\N' => '5.011', # Before this, an error. '\\V' => '5.009005', # Before this, parsed as 'V' '\\R' => '5.009005', '\\C' => '5.006', '\\X' => '5.006', ); sub perl_version_introduced { my ( $self ) = @_; my $content = $self->content(); if ( defined( my $minver = $introduced{$content} ) ) { return $minver; } if ( $content =~ m/ \A \\ [Pp] /smxg ) { # I must have read perl5113delta and thought this # represented the change they were talking about, but I sure # don't see it now. So, until things become clearer ... # $content =~ m/ \G .*? [\s=-] /smxgc # and return '5.011003'; return '5.006001'; } return MINIMUM_PERL; } } { my %removed = ( '\\C' => '5.023', # Before this, matched an octet ); sub perl_version_removed { my ( $self ) = @_; return $removed{ $self->content() }; } } # This is one of the larger complications of # https://rt.perl.org/Public/Bug/Display.html?id=128213 # where it transpired that un-escaped literal left curlies were not # giving warnings/errors in /.{/, /\p{...}{/, and /\P{...}{/, but were # for all the others that bin into this class (e.g. /\s{/). # Note that the perldelta for 5.25.1 and 5.26.0 do not acknowledge tha # phased deprecation, and pretend that everything was done on the phase # 1 schedule. This appears to be deliberate per # https://rt.perl.org/Ticket/Display.html?id=131352 sub __following_literal_left_curly_disallowed_in { my ( $self ) = @_; q<.> eq ( my $content = $self->content() ) and return LITERAL_LEFT_CURLY_REMOVED_PHASE_2; $content =~ m/ \A \\ p \{ /smxi and return LITERAL_LEFT_CURLY_REMOVED_PHASE_2; return LITERAL_LEFT_CURLY_REMOVED_PHASE_1; } sub __PPIX_TOKENIZER__regexp { my ( undef, $tokenizer, $character ) = @_; my $in_class = $tokenizer->cookie( COOKIE_CLASS ); if ( $character eq '.' ) { $in_class and return $tokenizer->make_token( 1, TOKEN_LITERAL ); return 1; } if ( my $accept = $tokenizer->find_regexp( qr{ \A \\ (?: [wWsSdDvVhHXRNC] | [Pp] \{ \s* \^? [\w:=\s-]+ \} | [Pp] [CLMNPSZ] # perluniprops for 5.26.1 ) }smx ) ) { if ( $in_class ) { my $match = $tokenizer->match(); # As of Perl 5.11.5, [\N] is a fatal error. '\\N' eq $match and return $tokenizer->make_token( $accept, TOKEN_UNKNOWN, { error => '\\N invalid inside character class', }, ); # \R is not recognized inside a character class. It # eventually ends up as a literal. '\\R' eq $match and return; } return $accept; } return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/CharClass/POSIX000755000765000024 013237102475 21327 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/CharClass/POSIX/Unknown.pm000444000765000024 433713237102475 23470 0ustar00tomstaff000000000000package PPIx::Regexp::Token::CharClass::POSIX::Unknown; use 5.006; use strict; use warnings; use base qw{ PPIx::Regexp::Token::CharClass::POSIX }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; our $VERSION = '0.055'; sub perl_version_introduced { # my ( $self ) = @_; return MINIMUM_PERL; } # Note that these guys are recognized by PPIx::Regexp::CharClass::POSIX, # and if one of them becomes supported that is where the change needs to # be made. # This is the handiest way to make this object represent a parse error. sub __PPIX_LEXER__finalize { return 1; } 1; __END__ =head1 NAME PPIx::Regexp::Token::CharClass::POSIX::Unknown - Represent an unknown or unsupported POSIX character class =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{ [[=a=]] }smx' ) -print() =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents POSIX character classes which are recognized but not supported by Perl. At the moment this means C<[=a=]> (equivalence classes), and C<[.ch.]> (collating symbols). B If any of these becomes supported by Perl in the future, they will become represented as L objects, with an appropriate C value. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2010-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType000755000765000024 013237102475 20520 5ustar00tomstaff000000000000PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/Assertion.pm000444000765000024 417713237102475 23173 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType::Assertion - Represent a look ahead or look behind assertion =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo(?=bar)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents the parenthesized look ahead and look behind assertions. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::GroupType::Assertion; use strict; use warnings; use base qw{ PPIx::Regexp::Token::GroupType }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; our $VERSION = '0.055'; { my %explanation = ( '?!' => 'Negative look-ahead assertion', '? 'Negative look-behind assertion', '?<=' => 'Positive look-behind assertion', '?=' => 'Positive look-ahead assertion', ); sub __explanation { return \%explanation; } } { my %perl_version_introduced = ( '?<=' => '5.005', '? '5.005', ); sub perl_version_introduced { my ( $self ) = @_; return $perl_version_introduced{ $self->unescaped_content() } || MINIMUM_PERL; } } # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub __defining_string { return ( '?=', '?<=', '?!', '?, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/BranchReset.pm000444000765000024 344313237102475 23417 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType::BranchReset - Represent a branch reset specifier =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?|(foo)|(bar))}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This token represents the specifier for a branch reset - namely the C that comes after the left parenthesis. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::GroupType::BranchReset; use strict; use warnings; use base qw{ PPIx::Regexp::Token::GroupType }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { my %explanation = ( '?|' => 'Re-use capture group numbers', ); sub __explanation { return \%explanation; } } sub perl_version_introduced { return '5.009005'; } sub __defining_string { return '?|'; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/Code.pm000444000765000024 635113237102475 22072 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType::Code - Represent one of the embedded code indicators =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?{print "hello world!\n")}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This method represents one of the embedded code indicators, either '?' or '??', in the zero-width assertion (?{ print "Hello, world!\n" }) or the old-style deferred expression syntax my $foo; $foo = qr{ foo (??{ $foo }) }smx; =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::GroupType::Code; use strict; use warnings; use base qw{ PPIx::Regexp::Token::GroupType }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { my %explanation = ( '??' => 'Evaluate code, use as regexp at this point', '?p' => 'Evaluate code, use as regexp at this point (removed in 5.9.5)', '?' => 'Evaluate code. Always matches.', ); sub __explanation { return \%explanation; } } { my %perl_version_introduced = ( '?' => '5.005', '?p' => '5.005', # Presumed. I can find no documentation. '??' => '5.006', ); sub perl_version_introduced { my ( $self ) = @_; return $perl_version_introduced{ $self->unescaped_content() } || '5.005'; } } { my %perl_version_removed = ( '?p' => '5.009005', ); sub perl_version_removed { my ( $self ) = @_; return $perl_version_removed{ $self->content() }; } } =begin comment sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; # Recognize '?{', '??{', or '?p{', the latter deprecated in Perl # 5.6, and removed in 5.10. The extra escapes are because the # non-open-bracket characters may appear as delimiters to the # expression. if ( my $accept = $tokenizer->find_regexp( qr{ \A \\? \? \\? [?p]? \{ }smx ) ) { --$accept; # Don't want the curly bracket. # Code token comes after. $tokenizer->expect( 'PPIx::Regexp::Token::Code' ); return $accept; } return; } =end comment =cut sub __defining_string { return ( { suffix => '{' }, '?', '??', '?p', ); } sub __match_setup { my ( undef, $tokenizer ) = @_; # Invocant unused $tokenizer->expect( qw{ PPIx::Regexp::Token::Code } ); return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/Modifier.pm000444000765000024 614513237102475 22757 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType::Modifier - Represent the modifiers in a modifier group. =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?i:foo)}smx' ) ->print(); =head1 INHERITANCE C is a L and a L. C has no descendants. =head1 DESCRIPTION This class represents the modifiers in a modifier group. The useful functionality comes from L. =head1 METHODS This class provides no public methods beyond those provided by its superclasses. =cut package PPIx::Regexp::Token::GroupType::Modifier; use strict; use warnings; use base qw{ PPIx::Regexp::Token::Modifier PPIx::Regexp::Token::GroupType }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; our $VERSION = '0.055'; { my %perl_version_introduced = ( '?:' => MINIMUM_PERL, ); sub perl_version_introduced { my ( $self ) = @_; my $content = $self->unescaped_content(); exists $perl_version_introduced{$content} and return $perl_version_introduced{$content}; my $ver = $self->SUPER::perl_version_introduced(); $ver > 5.005 and return $ver; return '5.005'; } } =begin comment # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character, $char_type ) = @_; # Note that the optional escapes are because any of the # non-open-bracket punctuation characters might be our delimiter. my $accept; $accept = $tokenizer->find_regexp( qr{ \A \\? [?] [[:lower:]]* \\? -? [[:lower:]]* \\? : }smx ) and return $accept; $accept = $tokenizer->find_regexp( qr{ \A \\? [?] \^ [[:lower:]]* \\? : }smx ) and return $accept; return; } =end comment =cut sub __make_group_type_matcher { return { '' => [ qr{ \A [?] [[:lower:]]* -? [[:lower:]]* : }smx, qr{ \A [?] \^ [[:lower:]]* : }smx, ], '?' => [ qr{ \A \\ [?] [[:lower:]]* -? [[:lower:]]* : }smx, qr{ \A \\ [?] \^ [[:lower:]]* : }smx, ], '-' => [ qr{ \A [?] [[:lower:]]* (?: \\ - )? [[:lower:]]* : }smx, qr{ \A [?] \^ [[:lower:]]* : }smx, ], ':' => [ qr{ \A [?] [[:lower:]]* -? [[:lower:]]* \\ : }smx, qr{ \A [?] \^ [[:lower:]]* \\ : }smx, ], }; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/NamedCapture.pm000444000765000024 555113237102475 23571 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType::NamedCapture - Represent a named capture =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?foo)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents a named capture specification. Its content will be something like one of the following: ? ?'NAME' ?P =head1 METHODS This class provides the following public methods. Methods not documented here are private, and unsupported in the sense that the author reserves the right to change or remove them without notice. =cut package PPIx::Regexp::Token::GroupType::NamedCapture; use strict; use warnings; use base qw{ PPIx::Regexp::Token::GroupType }; use Carp qw{ confess }; use PPIx::Regexp::Constant qw{ RE_CAPTURE_NAME }; our $VERSION = '0.055'; use constant TOKENIZER_ARGUMENT_REQUIRED => 1; sub __new { my ( $class, $content, %arg ) = @_; defined $arg{perl_version_introduced} or $arg{perl_version_introduced} = '5.009005'; my $self = $class->SUPER::__new( $content, %arg ); foreach my $name ( $arg{tokenizer}->capture() ) { defined $name or next; $self->{name} = $name; return $self; } confess 'Programming error - can not figure out capture name'; } # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub explain { my ( $self ) = @_; return sprintf q, $self->name(); } =head2 name This method returns the name of the capture. =cut sub name { my ( $self ) = @_; return $self->{name}; } sub __make_group_type_matcher { return { '' => [ qr/ \A [?] P? < ( @{[ RE_CAPTURE_NAME ]} ) > /smxo, qr/ \A [?] ' ( @{[ RE_CAPTURE_NAME ]} ) ' /smxo, ], '?' => [ qr/ \A \\ [?] P? < ( @{[ RE_CAPTURE_NAME ]} ) > /smxo, qr/ \A \\ [?] ' ( @{[ RE_CAPTURE_NAME ]} ) ' /smxo, ], q{'} => [ qr/ \A [?] P? < ( @{[ RE_CAPTURE_NAME ]} ) > /smxo, qr/ \A [?] \\ ' ( @{[ RE_CAPTURE_NAME ]} ) \\ ' /smxo, ], }; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/Script_Run.pm000444000765000024 353513237102475 23311 0ustar00tomstaff000000000000# Cargo cult to try to prevent CPAN from indexing package PPIx::Regexp::Token::GroupType::Script_Run; use 5.006; use strict; use warnings; use base qw{ PPIx::Regexp::Token::GroupType }; use Carp; our $VERSION = '0.055'; sub __explanation { return { '+script_run:' => 'All characters must be in same script', }; } sub perl_version_introduced { return '5.027008'; } sub __defining_string { return '+script_run:'; } 1; __END__ =head1 NAME PPIx::Regexp::Token::GroupType::Script_Run - Represent a script run specifier =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(+script_run:\d)}' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This token represents the specifier for a script run - namely the C<'+script_run:'> that comes after the left parenthesis. This is new with Perl 5.27.8. If this construction does not make it into Perl 5.28, this class will be retracted. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/Subexpression.pm000444000765000024 353313237102475 24070 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType::Subexpression - Represent an independent subexpression marker =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{foo(?>bar)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents the '?>' after a left parenthesis that identifies an independent subexpression. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::GroupType::Subexpression; use strict; use warnings; use base qw{ PPIx::Regexp::Token::GroupType }; our $VERSION = '0.055'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { my %explanation = ( '?>' => 'Match subexpression without backtracking', ); sub __explanation { return \%explanation; } } sub perl_version_introduced { ## my ( $self ) = @_; # Invocant unused return '5.005'; } sub __defining_string { return '?>'; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/lib/PPIx/Regexp/Token/GroupType/Switch.pm000444000765000024 506513237102475 22462 0ustar00tomstaff000000000000=head1 NAME PPIx::Regexp::Token::GroupType::Switch - Represent the introducing characters for a switch =head1 SYNOPSIS use PPIx::Regexp::Dumper; PPIx::Regexp::Dumper->new( 'qr{(?(1)foo|bar)}smx' ) ->print(); =head1 INHERITANCE C is a L. C has no descendants. =head1 DESCRIPTION This class represents the characters right after a left parenthesis that introduce a switch. Strictly speaking these characters are '?(', but this class only takes the '?'. =head1 METHODS This class provides no public methods beyond those provided by its superclass. =cut package PPIx::Regexp::Token::GroupType::Switch; use strict; use warnings; use base qw{ PPIx::Regexp::Token::GroupType }; our $VERSION = '0.055'; { my %explanation = ( '?' => q, ); sub __explanation { return \%explanation; } } sub perl_version_introduced { # my ( $self ) = @_; return '5.005'; } # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; =begin comment sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; # The optional escape is because any non-open-bracket character may # appear as the regular expression delimiter. if ( my $accept = $tokenizer->find_regexp( qr{ \A \\? \? \( }smx ) ) { # Leave the left paren, since it belongs to the condition. --$accept; $tokenizer->expect( qw{ PPIx::Regexp::Token::Condition } ); return $accept; } return; } =end comment =cut sub __defining_string { return ( { suffix => '(' }, '?', ); } sub __match_setup { my ( undef, $tokenizer ) = @_; # Invocant unused $tokenizer->expect( qw{ PPIx::Regexp::Token::Condition } ); return; } 1; __END__ =head1 SUPPORT Support is by the author. Please file bug reports at L, or in electronic mail to the author. =head1 AUTHOR Thomas R. Wyant, III F =head1 COPYRIGHT AND LICENSE Copyright (C) 2009-2018 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : PPIx-Regexp-0.055/t000755000765000024 013237102475 13125 5ustar00tomstaff000000000000PPIx-Regexp-0.055/t/basic.t000444000765000024 2762413237102475 14563 0ustar00tomstaff000000000000package main; use strict; use warnings; use lib qw{ inc }; use Test::More 0.88; require_ok( 'My::Module::Mock_Tokenizer' ) or BAIL_OUT; require_ok( 'PPI::Document' ) or BAIL_OUT( q{PPI::Document is a prerequisite. Without it, we're hosed.} ); require_ok( 'PPIx::Regexp' ) or BAIL_OUT; class_isa_ok( 'PPIx::Regexp', 'PPIx::Regexp::Node' ) or BAIL_OUT; require_ok( 'PPIx::Regexp::Constant' ); class_isa_ok( 'PPIx::Regexp::Constant', 'Exporter' ); require_ok( 'PPIx::Regexp::Dumper' ); class_isa_ok( 'PPIx::Regexp::Dumper', 'PPIx::Regexp::Support' ); isa_ok( PPIx::Regexp::Dumper->new( 'xyzzy' ), 'PPIx::Regexp::Dumper' ); require_ok( 'PPIx::Regexp::Element' ); require_ok( 'PPIx::Regexp::Lexer' ); class_isa_ok( 'PPIx::Regexp::Lexer', 'PPIx::Regexp::Support' ); require_ok( 'PPIx::Regexp::Node' ); class_isa_ok( 'PPIx::Regexp::Node', 'PPIx::Regexp::Element' ); require_ok( 'PPIx::Regexp::Node::Range' ); class_isa_ok( 'PPIx::Regexp::Node::Range', 'PPIx::Regexp::Node' ); require_ok( 'PPIx::Regexp::Node::Unknown' ); class_isa_ok( 'PPIx::Regexp::Node::Unknown', 'PPIx::Regexp::Node' ); require_ok( 'PPIx::Regexp::Structure' ); class_isa_ok( 'PPIx::Regexp::Structure', 'PPIx::Regexp::Node' ); require_ok( 'PPIx::Regexp::Structure::Assertion' ); class_isa_ok( 'PPIx::Regexp::Structure::Assertion', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::BranchReset' ); class_isa_ok( 'PPIx::Regexp::Structure::BranchReset', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::Capture' ); class_isa_ok( 'PPIx::Regexp::Structure::Capture', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::CharClass' ); class_isa_ok( 'PPIx::Regexp::Structure::CharClass', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::Code' ); class_isa_ok( 'PPIx::Regexp::Structure::Code', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::Main' ); class_isa_ok( 'PPIx::Regexp::Structure::Main', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::Modifier' ); class_isa_ok( 'PPIx::Regexp::Structure::Modifier', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::NamedCapture' ); class_isa_ok( 'PPIx::Regexp::Structure::NamedCapture', 'PPIx::Regexp::Structure::Capture' ); require_ok( 'PPIx::Regexp::Structure::Quantifier' ); class_isa_ok( 'PPIx::Regexp::Structure::Quantifier', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::Regexp' ); class_isa_ok( 'PPIx::Regexp::Structure::Regexp', 'PPIx::Regexp::Structure::Main' ); require_ok( 'PPIx::Regexp::Structure::Replacement' ); class_isa_ok( 'PPIx::Regexp::Structure::Replacement', 'PPIx::Regexp::Structure::Main' ); require_ok( 'PPIx::Regexp::Structure::Subexpression' ); class_isa_ok( 'PPIx::Regexp::Structure::Subexpression', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::Switch' ); class_isa_ok( 'PPIx::Regexp::Structure::Switch', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Structure::Unknown' ); class_isa_ok( 'PPIx::Regexp::Structure::Unknown', 'PPIx::Regexp::Structure' ); require_ok( 'PPIx::Regexp::Support' ); require_ok( 'PPIx::Regexp::Token' ); class_isa_ok( 'PPIx::Regexp::Token', 'PPIx::Regexp::Element' ); isa_ok( PPIx::Regexp::Token->__new( 'xyzzy' ), 'PPIx::Regexp::Token' ); require_ok( 'PPIx::Regexp::Token::Assertion' ); class_isa_ok( 'PPIx::Regexp::Token::Assertion', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Assertion->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Assertion' ); require_ok( 'PPIx::Regexp::Token::Backreference' ); class_isa_ok( 'PPIx::Regexp::Token::Backreference', 'PPIx::Regexp::Token::Reference' ); isa_ok( PPIx::Regexp::Token::Backreference->__new( '\\1' ), 'PPIx::Regexp::Token::Backreference' ); require_ok( 'PPIx::Regexp::Token::Backtrack' ); class_isa_ok( 'PPIx::Regexp::Token::Backtrack', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Backtrack->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Backtrack' ); require_ok( 'PPIx::Regexp::Token::CharClass' ); class_isa_ok( 'PPIx::Regexp::Token::CharClass', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::CharClass->__new( 'xyzzy' ), 'PPIx::Regexp::Token::CharClass' ); require_ok( 'PPIx::Regexp::Token::CharClass::POSIX' ); class_isa_ok( 'PPIx::Regexp::Token::CharClass::POSIX', 'PPIx::Regexp::Token::CharClass' ); isa_ok( PPIx::Regexp::Token::CharClass::POSIX->__new( 'xyzzy' ), 'PPIx::Regexp::Token::CharClass::POSIX' ); require_ok( 'PPIx::Regexp::Token::CharClass::Simple' ); class_isa_ok( 'PPIx::Regexp::Token::CharClass::Simple', 'PPIx::Regexp::Token::CharClass' ); isa_ok( PPIx::Regexp::Token::CharClass::Simple->__new( 'xyzzy' ), 'PPIx::Regexp::Token::CharClass::Simple' ); require_ok( 'PPIx::Regexp::Token::Code' ); class_isa_ok( 'PPIx::Regexp::Token::Code', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Code->__new( 'xyzzy', tokenizer => My::Module::Mock_Tokenizer->new(), ), 'PPIx::Regexp::Token::Code' ); require_ok( 'PPIx::Regexp::Token::Comment' ); class_isa_ok( 'PPIx::Regexp::Token::Comment', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Comment->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Comment' ); require_ok( 'PPIx::Regexp::Token::Condition' ); class_isa_ok( 'PPIx::Regexp::Token::Condition', 'PPIx::Regexp::Token::Reference' ); isa_ok( PPIx::Regexp::Token::Condition->__new( '(1)' ), 'PPIx::Regexp::Token::Condition' ); require_ok( 'PPIx::Regexp::Token::Control' ); class_isa_ok( 'PPIx::Regexp::Token::Control', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Control->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Control' ); require_ok( 'PPIx::Regexp::Token::Delimiter' ); class_isa_ok( 'PPIx::Regexp::Token::Delimiter', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Delimiter->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Delimiter' ); require_ok( 'PPIx::Regexp::Token::Greediness' ); class_isa_ok( 'PPIx::Regexp::Token::Greediness', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Greediness->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Greediness' ); require_ok( 'PPIx::Regexp::Token::GroupType' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::GroupType->__new( 'xyzzy' ), 'PPIx::Regexp::Token::GroupType' ); require_ok( 'PPIx::Regexp::Token::GroupType::Assertion' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::Assertion', 'PPIx::Regexp::Token::GroupType' ); isa_ok( PPIx::Regexp::Token::GroupType::Assertion->__new( 'xyzzy' ), 'PPIx::Regexp::Token::GroupType::Assertion' ); require_ok( 'PPIx::Regexp::Token::GroupType::BranchReset' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::BranchReset', 'PPIx::Regexp::Token::GroupType' ); isa_ok( PPIx::Regexp::Token::GroupType::BranchReset->__new( 'xyzzy' ), 'PPIx::Regexp::Token::GroupType::BranchReset' ); require_ok( 'PPIx::Regexp::Token::GroupType::Code' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::Code', 'PPIx::Regexp::Token::GroupType' ); isa_ok( PPIx::Regexp::Token::GroupType::Code->__new( 'xyzzy', tokenizer => My::Module::Mock_Tokenizer->new(), ), 'PPIx::Regexp::Token::GroupType::Code' ); require_ok( 'PPIx::Regexp::Token::GroupType::Modifier' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::Modifier', 'PPIx::Regexp::Token::GroupType' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::Modifier', 'PPIx::Regexp::Token::Modifier' ); isa_ok( PPIx::Regexp::Token::GroupType::Modifier->__new( 'xyzzy', tokenizer => My::Module::Mock_Tokenizer->new(), ), 'PPIx::Regexp::Token::GroupType::Modifier' ); require_ok( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::NamedCapture', 'PPIx::Regexp::Token::GroupType' ); isa_ok( PPIx::Regexp::Token::GroupType::NamedCapture->__new( 'xyzzy', tokenizer => My::Module::Mock_Tokenizer->new( capture => [ 'foo' ], ), ), 'PPIx::Regexp::Token::GroupType::NamedCapture' ); require_ok( 'PPIx::Regexp::Token::GroupType::Subexpression' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::Subexpression', 'PPIx::Regexp::Token::GroupType' ); isa_ok( PPIx::Regexp::Token::GroupType::Subexpression->__new( 'xyzzy' ), 'PPIx::Regexp::Token::GroupType::Subexpression' ); require_ok( 'PPIx::Regexp::Token::GroupType::Switch' ); class_isa_ok( 'PPIx::Regexp::Token::GroupType::Switch', 'PPIx::Regexp::Token::GroupType' ); isa_ok( PPIx::Regexp::Token::GroupType::Switch->__new( 'xyzzy' ), 'PPIx::Regexp::Token::GroupType::Switch' ); require_ok( 'PPIx::Regexp::Token::Interpolation' ); class_isa_ok( 'PPIx::Regexp::Token::Interpolation', 'PPIx::Regexp::Token::Code' ); isa_ok( PPIx::Regexp::Token::Interpolation->__new( 'xyzzy', tokenizer => My::Module::Mock_Tokenizer->new(), ), 'PPIx::Regexp::Token::Interpolation' ); require_ok( 'PPIx::Regexp::Token::Literal' ); class_isa_ok( 'PPIx::Regexp::Token::Literal', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Literal->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Literal' ); require_ok( 'PPIx::Regexp::Token::Modifier' ); class_isa_ok( 'PPIx::Regexp::Token::Modifier', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Modifier->__new( 'xyzzy', tokenizer => My::Module::Mock_Tokenizer->new(), ), 'PPIx::Regexp::Token::Modifier' ); require_ok( 'PPIx::Regexp::Token::NoOp' ); class_isa_ok( 'PPIx::Regexp::Token::NoOp', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::NoOp->__new( 'xyzzy' ), 'PPIx::Regexp::Token::NoOp' ); require_ok( 'PPIx::Regexp::Token::Operator' ); class_isa_ok( 'PPIx::Regexp::Token::Operator', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Operator->__new( 'xyzzy', tokenizer => My::Module::Mock_Tokenizer->new(), ), 'PPIx::Regexp::Token::Operator' ); require_ok( 'PPIx::Regexp::Token::Quantifier' ); class_isa_ok( 'PPIx::Regexp::Token::Quantifier', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Quantifier->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Quantifier' ); require_ok( 'PPIx::Regexp::Token::Recursion' ); class_isa_ok( 'PPIx::Regexp::Token::Recursion', 'PPIx::Regexp::Token::Reference' ); isa_ok( PPIx::Regexp::Token::Recursion->__new( '(?1)' ), 'PPIx::Regexp::Token::Recursion' ); require_ok( 'PPIx::Regexp::Token::Reference' ); class_isa_ok( 'PPIx::Regexp::Token::Reference', 'PPIx::Regexp::Token' ); # This is an abstract class and should never be instantiated in the # first place. # isa_ok( PPIx::Regexp::Token::Reference->__new( 'xyzzy' ), # 'PPIx::Regexp::Token::Reference' ); require_ok( 'PPIx::Regexp::Token::Structure' ); class_isa_ok( 'PPIx::Regexp::Token::Structure', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Structure->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Structure' ); require_ok( 'PPIx::Regexp::Token::Unknown' ); class_isa_ok( 'PPIx::Regexp::Token::Unknown', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Unknown->__new( 'xyzzy', error => 'bogus' ), 'PPIx::Regexp::Token::Unknown' ); require_ok( 'PPIx::Regexp::Token::Unmatched' ); class_isa_ok( 'PPIx::Regexp::Token::Unmatched', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Unmatched->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Unmatched' ); require_ok( 'PPIx::Regexp::Token::Whitespace' ); class_isa_ok( 'PPIx::Regexp::Token::Whitespace', 'PPIx::Regexp::Token::NoOp' ); isa_ok( PPIx::Regexp::Token::Whitespace->__new( 'xyzzy' ), 'PPIx::Regexp::Token::Whitespace' ); require_ok( 'PPIx::Regexp::Tokenizer' ); class_isa_ok( 'PPIx::Regexp::Tokenizer', 'PPIx::Regexp::Support' ); isa_ok( PPIx::Regexp::Tokenizer->new( 'xyzzy' ), 'PPIx::Regexp::Tokenizer' ); require_ok( 'PPIx::Regexp::StringTokenizer' ); class_isa_ok( 'PPIx::Regexp::StringTokenizer', 'PPIx::Regexp::Tokenizer' ); isa_ok( PPIx::Regexp::StringTokenizer->new( 'xyzzy' ), 'PPIx::Regexp::StringTokenizer' ); done_testing; sub class_isa_ok { my ( $class, $isa ) = @_; @_ = ( eval { $class->isa( $isa ) }, "$class isa $isa", ); goto &ok, } 1; __END__ # ex: set textwidth=72 : PPIx-Regexp-0.055/t/fuzz.t000444000765000024 126013237102475 14444 0ustar00tomstaff000000000000package main; use 5.006; use strict; use warnings; use lib qw{ inc }; use My::Module::Test; use My::Module::Test qw{ __quote }; note <<'EOD'; Obviously this is not a true fuzz test, just a collection of pathological strings discovered via fuzz testing. Because the parse of an invalid string may change, we just see if the code survived the test. EOD survival( 'x//' ); survival( ' ' ); done_testing; sub survival { my ( $expr ) = @_; my $title = join ' ', 'Parse', __quote( $expr ); eval { PPIx::Regexp->new( $expr ); 1; } and do { @_ = ( $title ); goto &pass; } or do { @_ = ( "$title failed: $@" ); goto &fail; }; } 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/t/parse.t000444000765000024 110135013237102475 14642 0ustar00tomstaff000000000000package main; use strict; use warnings; use lib qw{ inc }; use My::Module::Test; # NOTE: It is intended that all individual tests in this file be # generated by PPIx::Regexp::Dumper. Special tests should go in # t/unit.t. tokenize( '' ); count ( 0 ); parse ( '' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 0 ); tokenize( 'fubar' ); count ( 1 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( 'fubar' ); parse ( 'fubar' ); value ( failures => [], 1); class ( 'PPIx::Regexp' ); count ( 1 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( 'fubar' ); tokenize( '/(/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(/' ); value ( failures => [], 1); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 0 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, finish => 0 ); class ( undef ); content ( undef ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/)/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/)/' ); value ( failures => [], 1); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Unmatched' ); content ( ')' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm//' ); count ( 4 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm//' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 0 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr\'\'' ); count ( 4 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr\'\'' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 0 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr /foo/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr /foo/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm{}' ); count ( 4 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm{}' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 0 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm{}smx' ); count ( 4 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); parse ( 'm{}smx' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 0 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); tokenize( 'm{foo}' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm{foo}' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/m{foo\\t\\0334\\o{61}\\cK\\xBB\\_\\{\\}\\!/' ); count ( 19 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'm' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\t' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\033' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 4 ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\o{61}' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\cK' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\xBB' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\_' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\{' ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\}' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\!' ); choose ( 17 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 18 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/m{foo\\t\\0334\\o{61}\\cK\\xBB\\_\\{\\}\\!/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 15 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'm' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\t' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\033' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 4 ); choose ( child => 1, child => 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\o{61}' ); choose ( child => 1, child => 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\cK' ); choose ( child => 1, child => 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\xBB' ); choose ( child => 1, child => 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\_' ); choose ( child => 1, child => 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\{' ); choose ( child => 1, child => 13 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\}' ); choose ( child => 1, child => 14 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\!' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\\\{/' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\\\{/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\N{LATIN SMALL LETTER A}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\N{LATIN SMALL LETTER A}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\N{LATIN SMALL LETTER A}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\N{LATIN SMALL LETTER A}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\C{4}/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\C' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 4 ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\C{4}/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\C' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 1 ); choose ( child => 1, child => 1, start => [] ); count ( 1 ); choose ( child => 1, child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 1, type => [] ); count ( 0 ); choose ( child => 1, child => 1, finish => [] ); count ( 1 ); choose ( child => 1, child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 4 ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(\\C)/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\C' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(\\C)/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\C' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr{foo+}' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr{foo+}' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr{foo?}' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr{foo?}' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr{foo*}' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr{foo*}' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr{foo*bar+}' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr{foo*bar+}' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 8 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr{+}' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '+' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr{+}' ); value ( failures => [], 1); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '+' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr/foo{3}/' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '3' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr/foo{3}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 1 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr/foo{3,}/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '3' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr/foo{3,}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 2 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 3, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr/foo{3,5}/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '3' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '5' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr/foo{3,5}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 3 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 3, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( child => 1, child => 3, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 5 ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr/foo{3,$bar}/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$bar' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr/foo{3,$bar}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 3 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 3, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( child => 1, child => 3, child => 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$bar' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr/foo{,3}/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '3' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr/foo{,3}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/{}/' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/{}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/x{}/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/x{}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/{2}/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '2' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/{2}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 2 ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/f{oo/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/f{oo/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(f{oo)/' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(f{oo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 4 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/{?+}/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '+' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/{?+}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/./' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/./' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\\\d{3,5}+.*?/' ); count ( 15 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'd' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '3' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '5' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '?' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\\\d{3,5}+.*?/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'd' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 3 ); choose ( child => 1, child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( child => 1, child => 2, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 5 ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '?' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/\\w+\\W*\\s?\\S\\d\\D\\v\\V\\h\\H/' ); count ( 17 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\W' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\s' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\S' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\d' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\D' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\v' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\V' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\h' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\H' ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/\\w+\\W*\\s?\\S\\d\\D\\v\\V\\h\\H/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 13 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\W' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\s' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\S' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\d' ); choose ( child => 1, child => 8 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\D' ); choose ( child => 1, child => 9 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\v' ); choose ( child => 1, child => 10 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\V' ); choose ( child => 1, child => 11 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\h' ); choose ( child => 1, child => 12 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\H' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/\\p{Punctuation}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\p{Punctuation}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/\\p{Punctuation}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\p{Punctuation}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/\\p{My::InEvenChars}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\p{My::InEvenChars}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/\\p{My::InEvenChars}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\p{My::InEvenChars}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/foo bar/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/foo bar/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/foo bar/x' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); parse ( 'm/foo bar/x' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); tokenize( '/$foo/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/$foo/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/${foo}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '${foo}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/${foo}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '${foo}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm\'$foo\'' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm\'$foo\'' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/A $foo{bar} baz/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo{bar}' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/A $foo{bar} baz/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo{bar}' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/A $foo{3} baz/' ); count ( 14 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '3' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/A $foo{3} baz/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 8 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 1 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/A @{[ scalar time ]} baz/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '@{[ scalar time ]}' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/A @{[ scalar time ]} baz/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '@{[ scalar time ]}' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/[$foo]/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/[$foo]/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 's/([\\x00-\\x1f])/$UNPRINTABLE[ord($1)]/g' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\x00' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\x1f' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$UNPRINTABLE[ord($1)]' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'g' ); parse ( 's/([\\x00-\\x1f])/$UNPRINTABLE[ord($1)]/g' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Node::Range' ); count ( 3 ); choose ( child => 1, child => 0, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\x00' ); choose ( child => 1, child => 0, child => 0, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( child => 1, child => 0, child => 0, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\x1f' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 2, start => [] ); count ( 0 ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$UNPRINTABLE[ord($1)]' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'g' ); tokenize( 's/$$foo{bar}/$$bar{foo}/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$$foo{bar}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$$bar{foo}' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 's/$$foo{bar}/$$bar{foo}/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$$foo{bar}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 2, start => [] ); count ( 0 ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$$bar{foo}' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/a|b/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/a|b/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/$|$($)@+@-/' ); count ( 14 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '@' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '@' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '-' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/$|$($)@+@-/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 8 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '@' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '@' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '-' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/$-$+$$$[$]$-[0]$+[0]$-{foo}$+{foo}/' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$-' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$+' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$$' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$[' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$]' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$-[0]' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$+[0]' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$-{foo}' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$+{foo}' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/$-$+$$$[$]$-[0]$+[0]$-{foo}$+{foo}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 9 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$-' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$+' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$$' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$[' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$]' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$-[0]' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$+[0]' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$-{foo}' ); choose ( child => 1, child => 8 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$+{foo}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/\\Q\\w$foo\\\\E\\E/' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\Q' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\w' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'E' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\E' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/\\Q\\w$foo\\\\E\\E/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 6 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\Q' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\w' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'E' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\E' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\lX\\uy\\LFOO\\Ubar\\Q.^\\E/' ); count ( 20 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\l' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'X' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\u' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'y' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\L' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'F' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'O' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'O' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\U' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\Q' ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '.' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '^' ); choose ( 17 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\E' ); choose ( 18 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 19 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\lX\\uy\\LFOO\\Ubar\\Q.^\\E/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 16 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\l' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'X' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\u' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'y' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\L' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'F' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'O' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'O' ); choose ( child => 1, child => 8 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\U' ); choose ( child => 1, child => 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 1, child => 12 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\Q' ); choose ( child => 1, child => 13 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '.' ); choose ( child => 1, child => 14 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '^' ); choose ( child => 1, child => 15 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\E' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/$foo?/' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/$foo?/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/$#foo/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$#foo' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/$#foo/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$#foo' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/$#$foo{3}/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$#$foo' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/$#$foo{3}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$#$foo' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 1 ); choose ( child => 1, child => 1, start => [] ); count ( 1 ); choose ( child => 1, child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 1, type => [] ); count ( 0 ); choose ( child => 1, child => 1, finish => [] ); count ( 1 ); choose ( child => 1, child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/$#{^_foo}{4}/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$#{^_foo}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 4 ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/$#{^_foo}{4}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$#{^_foo}' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 1 ); choose ( child => 1, child => 1, start => [] ); count ( 1 ); choose ( child => 1, child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 1, type => [] ); count ( 0 ); choose ( child => 1, child => 1, finish => [] ); count ( 1 ); choose ( child => 1, child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 4 ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/foo\\Ub\\wr\\Ebaz/' ); count ( 15 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\U' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\E' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/foo\\Ub\\wr\\Ebaz/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 11 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\U' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\E' ); choose ( child => 1, child => 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\Fu/' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\F' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'u' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\Fu/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\F' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'u' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/ foo (?# match foo )+/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '(?# match foo )' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/ foo (?# match foo )+/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '(?# match foo )' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/ foo # match foo /smx' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '# match foo ' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); parse ( 'm/ foo # match foo /smx' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 5 ); choose ( child => 1, start => [] ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '# match foo ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); tokenize( '/^#/x' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '^' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); parse ( '/^#/x' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '^' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); tokenize( 'm/[# ]/x' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '#' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); parse ( 'm/[# ]/x' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 2 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '#' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); tokenize( '/(?x)\\1?\\g{-1}*\\k{1,3}+/' ); count ( 19 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{-1}' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\k' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); choose ( 17 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 18 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?x)\\1?\\g{-1}*\\k{1,3}+/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 8 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{-1}' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\k' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 3 ); choose ( child => 1, child => 6, start => [] ); count ( 1 ); choose ( child => 1, child => 6, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 6, type => [] ); count ( 0 ); choose ( child => 1, child => 6, finish => [] ); count ( 1 ); choose ( child => 1, child => 6, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 6, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( child => 1, child => 6, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( child => 1, child => 6, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?x)\\1?\\g{-1}*\\k{1,3}+/' ); count ( 19 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{-1}' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\k' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); choose ( 17 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 18 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?x)\\1?\\g{-1}*\\k{1,3}+/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 8 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{-1}' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\k' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Structure::Quantifier' ); count ( 3 ); choose ( child => 1, child => 6, start => [] ); count ( 1 ); choose ( child => 1, child => 6, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( child => 1, child => 6, type => [] ); count ( 0 ); choose ( child => 1, child => 6, finish => [] ); count ( 1 ); choose ( child => 1, child => 6, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( child => 1, child => 6, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( child => 1, child => 6, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ',' ); choose ( child => 1, child => 6, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 3 ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # In the replacement string only \n is a backreference tokenize( 's/(x)/\\g{1}\\1/' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\g' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 's/(x)/\\g{1}\\1/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 5 ); choose ( child => 2, start => [] ); count ( 0 ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\g' ); choose ( child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 2, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( child => 2, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2, child => 4 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 's/(foo)/\\1bar/g' ); count ( 14 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'g' ); parse ( 's/(foo)/\\1bar/g' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 4 ); choose ( child => 2, start => 0 ); class ( undef ); content ( undef ); choose ( child => 2, type => 0 ); class ( undef ); content ( undef ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); choose ( child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 2, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 2, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'g' ); tokenize( 's/x/$1/e' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '$1' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'e' ); parse ( 's/x/$1/e' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 2, start => [] ); count ( 0 ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '$1' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'e' ); tokenize( 's/x/$1/eeg' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '$1' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'eeg' ); parse ( 's/x/$1/eeg' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '$1' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'eeg' ); false ( asserts => [ 'e' ] ); true ( asserts => [ 'ee' ] ); true ( asserts => [ 'g' ] ); tokenize( '/^\\A\\b\\B\\G\\Z\\z$/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '^' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\A' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\b' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\B' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\G' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\Z' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\z' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/^\\A\\b\\B\\G\\Z\\z$/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 8 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '^' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\A' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\b' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\B' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\G' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\Z' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\z' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/(?smx)bar/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '(?smx)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/(?smx)bar/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '(?smx)' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/(?smx:foo)bar/' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?smx:' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/(?smx:foo)bar/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?smx:' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?-x:#1)#2/x' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?-x:' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '#' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#2' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); parse ( '/(?-x:#1)#2/x' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 2 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?-x:' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '#' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#2' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); tokenize( '/(?-x)#1(?x)#2/x' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '(?-x)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '#' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '(?x)' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#2' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); parse ( '/(?-x)#1(?x)#2/x' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 5 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '(?-x)' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '#' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 1 ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '(?x)' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#2' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); tokenize( '/(?$foo:$bar)/' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ':' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$bar' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?$foo:$bar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 3 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?' ); choose ( child => 1, child => 0, type => 1 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 1, child => 0, type => 2 ); class ( 'PPIx::Regexp::Token::GroupType' ); content ( ':' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$bar' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?$foo)$bar/' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$bar' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?$foo)$bar/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 0 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 2 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?' ); choose ( child => 1, child => 0, type => 1 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$bar' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?$on-$off:$foo)/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$on' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '-' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$off' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ':' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?$on-$off:$foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 5 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?' ); choose ( child => 1, child => 0, type => 1 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$on' ); choose ( child => 1, child => 0, type => 2 ); class ( 'PPIx::Regexp::Token::GroupType' ); content ( '-' ); choose ( child => 1, child => 0, type => 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$off' ); choose ( child => 1, child => 0, type => 4 ); class ( 'PPIx::Regexp::Token::GroupType' ); content ( ':' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?$on-$off)$foo/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$on' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '-' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$off' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?$on-$off)$foo/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 0 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 4 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?' ); choose ( child => 1, child => 0, type => 1 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$on' ); choose ( child => 1, child => 0, type => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '-' ); choose ( child => 1, child => 0, type => 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$off' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$foo' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?bar)/' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?bar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?\'foo\'bar)/' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?\'foo\'' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?\'foo\'bar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?\'foo\'' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?Pbar)/' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?P' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?Pbar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?P' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr/(?\\w)/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr/(?\\w)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/foo(?=bar)/' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?=' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/foo(?=bar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Assertion' ); count ( 3 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 3, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?=' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 3, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/foo(?!bar)/' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?!' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/foo(?!bar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Assertion' ); count ( 3 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 3, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?!' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 3, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?<=foo)bar/' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?<=' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?<=foo)bar/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Assertion' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?<=' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(? [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Assertion' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '? 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(*PRUNE:foo)x/' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Backtrack' ); content ( '(*PRUNE:foo)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(*PRUNE:foo)x/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Backtrack' ); content ( '(*PRUNE:foo)' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/[^]0-9\\w]/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '^' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ']' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '0' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '9' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'm/[^]0-9\\w]/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '^' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ']' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Node::Range' ); count ( 3 ); choose ( child => 1, child => 0, child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 0 ); choose ( child => 1, child => 0, child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( child => 1, child => 0, child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 9 ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'm/ [\\w\\{] /smx' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); parse ( 'm/ [\\w\\{] /smx' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 2 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\{' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); tokenize( 'm/ [\\w{] /smx' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); parse ( 'm/ [\\w{] /smx' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 2 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '{' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); tokenize( 'm/ [-\\\\^\\$\\]] /smx' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '-' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '^' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\$' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\]' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); parse ( 'm/ [-\\\\^\\$\\]] /smx' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 5 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '-' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '^' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\$' ); choose ( child => 1, child => 0, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\]' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); tokenize( 'm/ [\\\\\\^^.\\||()\\[] /smx' ); count ( 17 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\^' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '^' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '.' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\|' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '|' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '(' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ')' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\[' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); parse ( 'm/ [\\\\\\^^.\\||()\\[] /smx' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'm' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 9 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\^' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '^' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '.' ); choose ( child => 1, child => 0, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\|' ); choose ( child => 1, child => 0, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '|' ); choose ( child => 1, child => 0, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '(' ); choose ( child => 1, child => 0, child => 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ')' ); choose ( child => 1, child => 0, child => 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\[' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); tokenize( '/[[:upper:]]+[[:^lower:]]?/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); content ( '[:upper:]' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); content ( '[:^lower:]' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/[[:upper:]]+[[:^lower:]]?/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); content ( '[:upper:]' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 2, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); content ( '[:^lower:]' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 'qr{ \\A \\\\ x \\{ \\w+ \\} }smx' ); count ( 18 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\A' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\{' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\}' ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 17 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); parse ( 'qr{ \\A \\\\ x \\{ \\w+ \\} }smx' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 13 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\A' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\\\' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\{' ); choose ( child => 1, child => 7 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 8 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 1, child => 9 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '+' ); choose ( child => 1, child => 10 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\}' ); choose ( child => 1, child => 12 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); tokenize( 's/foo\\Kbar/baz/' ); count ( 15 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\K' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 's/foo\\Kbar/baz/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 7 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\K' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 3 ); choose ( child => 2, start => 0 ); class ( undef ); content ( undef ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 2, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 's/$CR?$LF/\\n/g' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$CR' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$LF' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\n' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'g' ); parse ( 's/$CR?$LF/\\n/g' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$CR' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$LF' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 2, start => 0 ); class ( undef ); content ( undef ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\n' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'g' ); tokenize( '/$RE{delimited}{-delim=>\'"\'}{-esc=>\'\\\\\'}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$RE{delimited}{-delim=>\'"\'}{-esc=>\'\\\\\'}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/$RE{delimited}{-delim=>\'"\'}{-esc=>\'\\\\\'}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$RE{delimited}{-delim=>\'"\'}{-esc=>\'\\\\\'}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 's%(.*?${/})%%o' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '%' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '?' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '${/}' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '%' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '%' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'o' ); parse ( 's%(.*?${/})%%o' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '%' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '%' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 4 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '*' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '?' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '${/}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 0 ); choose ( child => 2, start => [] ); count ( 0 ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '%' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'o' ); tokenize( 's[foo] [bar]' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '[' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( ']' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '[' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( ']' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 's[foo] [bar]' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 5 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '[' ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( ']' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 3 ); choose ( child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '[' ); choose ( child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( ']' ); choose ( child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 3, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 3, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?{ print "Hello, world!\\n" })/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{ print "Hello, world!\\n" }' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?{ print "Hello, world!\\n" })/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Code' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{ print "Hello, world!\\n" }' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(??{ $foo })/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '??' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{ $foo }' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(??{ $foo })/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Code' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '??' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{ $foo }' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?|(foo))/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::BranchReset' ); content ( '?|' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?|(foo))/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::BranchReset' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::BranchReset' ); content ( '?|' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 3 ); choose ( child => 1, child => 0, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?1)/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?1)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?1)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?1)' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?+2)/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?+2)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?+2)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?+2)' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?-3)/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?-3)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?-3)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?-3)' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?R)/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?R)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?R)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?R)' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?&foo)/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?&foo)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?&foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?&foo)' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?P>foo)/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?P>foo)' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?P>foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?P>foo)' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/foo(?>bar)/' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::GroupType::Subexpression' ); content ( '?>' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/foo(?>bar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Structure::Subexpression' ); count ( 3 ); choose ( child => 1, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 3, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Subexpression' ); content ( '?>' ); choose ( child => 1, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 3, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 3, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(})/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '}' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/]/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/]/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ']' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(])/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(])/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ']' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?(1)foo)/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(1)' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?(1)foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(1)' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?(1)foo|bar)/' ); count ( 15 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(1)' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?(1)foo|bar)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 8 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(1)' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 4 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( child => 1, child => 0, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 0, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 0, child => 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?(1)foo|bar|baz)/' ); count ( 19 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(1)' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 17 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 18 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?(1)foo|bar|baz)/' ); value ( failures => [], 1); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 12 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(1)' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 4 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( child => 1, child => 0, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 0, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 0, child => 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 1, child => 0, child => 8 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '|' ); choose ( child => 1, child => 0, child => 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 0, child => 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 0, child => 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?()foo)/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '()' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?()foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '()' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?(\'baz\')foo)/' ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(\'baz\')' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?(\'baz\')foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(\'baz\')' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?(?{0})foo)/' ); count ( 14 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{0}' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?(?{0})foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Structure::Code' ); count ( 1 ); choose ( child => 1, child => 0, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?' ); choose ( child => 1, child => 0, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{0}' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # TODO /(?(R\d*)..)/, /(?(R&name)...)/, /(?(DEFINE)...)/. tokenize( '/ ( ?<= bar ) /x' ); count ( 15 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?<=' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); parse ( '/ ( ?<= bar ) /x' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Assertion' ); count ( 4 ); choose ( child => 1, child => 0, start => [] ); count ( 2 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, type => [] ); count ( 2 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?<=' ); choose ( child => 1, child => 0, type => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); tokenize( 'qr!(?<\\!foo)bar!' ); count ( 13 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '!' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?<\\!' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '!' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 'qr!(?<\\!foo)bar!' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qr' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '!' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '!' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Assertion' ); count ( 3 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Assertion' ); content ( '?<\\!' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?{ foo } )/' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{ foo }' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?{ foo } )/' ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Code' ); count ( 2 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '{ foo }' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 's/\\b/\\b/' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\b' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\b' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); finis (); parse ( 's/\\b/\\b/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\b' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 2, start => [] ); count ( 0 ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\b' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( 's\\/$\\\\' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\\' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '/' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\\' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\\' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 's\\/$\\\\' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\\' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\\' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '/' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '$' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 0 ); choose ( child => 2, start => [] ); count ( 0 ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\\' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/ . /' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/ . /' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/ . /', default_modifiers => [ 'smx' ] ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/ . /', default_modifiers => [ 'smx' ] ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '.' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/(?[ \\P{Foo} & ( [:alpha:] | [ . \\d ] - [9] ) ])/' ); count ( 33 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(?[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\P{Foo}' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '&' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); content ( '[:alpha:]' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 14 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 15 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 16 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '.' ); choose ( 17 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 18 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\d' ); choose ( 19 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 20 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 21 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 22 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( 23 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 24 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 25 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 9 ); choose ( 26 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 27 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 28 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 29 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 30 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '])' ); choose ( 31 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 32 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?[ \\P{Foo} & ( [:alpha:] | [ . \\d ] - [9] ) ])/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::RegexSet' ); count ( 6 ); choose ( child => 1, child => 0, start => [] ); count ( 2 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(?[' ); choose ( child => 1, child => 0, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '])' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\P{Foo}' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '&' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4 ); class ( 'PPIx::Regexp::Structure' ); count ( 10 ); choose ( child => 1, child => 0, child => 4, start => [] ); count ( 2 ); choose ( child => 1, child => 0, child => 4, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 4, start => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 4, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 4, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 4, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); content ( '[:alpha:]' ); choose ( child => 1, child => 0, child => 4, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, child => 2 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( child => 1, child => 0, child => 4, child => 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, child => 4 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 5 ); choose ( child => 1, child => 0, child => 4, child => 4, start => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 4, child => 4, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, child => 4, child => 4, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 4, child => 4, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 4, child => 4, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 4, child => 4, child => 0 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, child => 4, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '.' ); choose ( child => 1, child => 0, child => 4, child => 4, child => 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, child => 4, child => 3 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\d' ); choose ( child => 1, child => 0, child => 4, child => 4, child => 4 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, child => 5 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, child => 6 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( child => 1, child => 0, child => 4, child => 7 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4, child => 8 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, child => 4, child => 8, start => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 4, child => 8, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, child => 4, child => 8, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 4, child => 8, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 4, child => 8, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 4, child => 8, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 9 ); choose ( child => 1, child => 0, child => 4, child => 9 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 5 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # The /n qualifier prevents parens from capturing. tokenize( '/(foo)/n' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'n' ); parse ( '/(foo)/n' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure' ); count ( 3 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'n' ); # The /n qualifier does not prevent named captures tokenize( '/(?foo)/n' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'n' ); parse ( '/(?foo)/n' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 3 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'n' ); note q; tokenize( '/(?x-i:f o o)/' ); count ( 12 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?x-i:' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(?x-i:f o o)/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 5 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?x-i:' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 0, child => 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\N{}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::NoOp' ); content ( '\\N{}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\N{}/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 0 ); choose ( child => 1, start => [] ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::NoOp' ); content ( '\\N{}' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\N{}/', strict => 1 ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '\\N{}' ); error ( 'Empty Unicode character name prohibited by "use re \'strict\'"' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\N{}/', strict => 1 ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '\\N{}' ); error ( 'Empty Unicode character name prohibited by "use re \'strict\'"' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/[A-Z]/', strict => 1 ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'Z' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/[A-Z]/', strict => 1 ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Node::Range' ); count ( 3 ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( child => 1, child => 0, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( child => 1, child => 0, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'Z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/[A-z]/', strict => 1 ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/[A-z]/', strict => 1 ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Node::Unknown' ); count ( 3 ); error ( 'Non-portable range ends prohibited by "use re \'strict\'"' ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'A' ); choose ( child => 1, child => 0, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( child => 1, child => 0, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # Unterminated replacement tokenize( 's/foo/' ); count ( 1 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( 's/foo/' ); error ( 'Tokenizer found mismatched replacement delimiters' ); parse ( 's/foo/' ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 1 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( 's/foo/' ); error ( 'Tokenizer found mismatched replacement delimiters' ); # bracketed replacement with embedded Perl comment tokenize( 's{foo} #{bar} {baz}' ); count ( 14 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#{bar} ' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 11 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( 13 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( 's{foo} #{bar} {baz}' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 6 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '#{bar} ' ); choose ( child => 4 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 3 ); choose ( child => 4, start => [] ); count ( 1 ); choose ( child => 4, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 4, type => [] ); count ( 0 ); choose ( child => 4, finish => [] ); count ( 1 ); choose ( child => 4, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 4, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 4, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 4, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/\\b{/' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\b' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '{' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/\\b{/' ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\b' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '{' ); error ( 'Unterminated bound type' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); tokenize( '/[ a]/xx' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'xx' ); parse ( '/[ a]/xx' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 2 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'xx' ); tokenize( '/(+script_run:\\w)/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Script_Run' ); content ( '+script_run:' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); parse ( '/(+script_run:\\w)/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Script_Run' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Script_Run' ); content ( '+script_run:' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); done_testing; 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/t/string.t000444000765000024 3305313237102475 15001 0ustar00tomstaff000000000000package main; use 5.006; use strict; use warnings; use lib qw{ inc }; use My::Module::Test; # NOTE: It is intended that all individual tests in this file be # generated by PPIx::Regexp::Dumper. Special tests should go in # t/unit.t. tokenize( '\'\'', parse => 'string' ); count ( 3 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); parse ( '\'\'', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 0 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); tokenize( '"x"', parse => 'string' ); count ( 4 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '"' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '"' ); parse ( '"x"', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '"' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '"' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); tokenize( '`$x`', parse => 'string' ); count ( 4 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '`' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '`' ); parse ( '`$x`', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '`' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '`' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); tokenize( 'q{$x}', parse => 'string' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'q' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '$' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); parse ( 'q{$x}', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'q' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '$' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); tokenize( 'qq', parse => 'string' ); count ( 10 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qq' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '<' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '${x}' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '>' ); parse ( 'qq', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qq' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 7 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '<' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '>' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '${x}' ); choose ( child => 1, child => 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'b' ); choose ( child => 1, child => 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'r' ); tokenize( 'qx{$x}', parse => 'string' ); count ( 4 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qx' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); parse ( 'qx{$x}', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qx' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '{' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '}' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); tokenize( 'qx\'$x\'', parse => 'string' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qx' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '$' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); parse ( 'qx\'$x\'', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 'qx' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '\'' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '$' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); tokenize( '< 'string' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '<<' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\n" ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); parse ( '< 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 2 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '<<' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 2 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\n" ); tokenize( '<< "EOD" $x EOD ', parse => 'string' ); count ( 6 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '<<' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( qq{"EOD"\n} ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\n" ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); parse ( '<< "EOD" $x EOD ', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '<<' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 2 ); choose ( child => 2, start => [] ); count ( 1 ); choose ( child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( qq{"EOD"\n} ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x' ); choose ( child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\n" ); tokenize( '<< \'EOD\' $x EOD ', parse => 'string' ); count ( 7 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '<<' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "'EOD'\n" ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '$' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\n" ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); parse ( '<< \'EOD\' $x EOD ', parse => 'string' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '<<' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Replacement' ); count ( 3 ); choose ( child => 2, start => [] ); count ( 1 ); choose ( child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "'EOD'\n" ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( "EOD\n" ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '$' ); choose ( child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 2, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\n" ); done_testing; 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/t/string_unit.t000444000765000024 44313237102475 15775 0ustar00tomstaff000000000000package main; use 5.006; use strict; use warnings; use lib qw{ inc }; use My::Module::Test; parse ( '"x"', parse => 'string' ); value ( failures => [], 0 ); value ( regular_expression => [], undef ); value ( modifier => [], undef ); done_testing; 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/t/unit.t000444000765000024 17645113237102475 14504 0ustar00tomstaff000000000000package main; use strict; use warnings; use lib qw{ inc }; use PPI::Document; use My::Module::Test; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; use Scalar::Util qw{ refaddr }; my $is_ascii = ord( "\t" ) == 9; # per perlebcdic my $have_charnames; BEGIN { eval { require charnames; charnames->import( qw{ :full } ); $have_charnames = charnames->can( 'vianame' ); }; } tokenize( {}, '-notest' ); # We don't know how to tokenize a hash reference. equals ( undef, 'We did not get an object' ); value ( errstr => [], 'HASH not supported' ); parse ( {}, '-notest' ); # If we can't tokenize it, we surely can't parse it. equals ( undef, 'We did not get an object' ); value ( errstr => [], 'HASH not supported' ); parse ( 'fubar' ); # We can't make anything of this. value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); value ( capture_names => [], undef ); value ( max_capture_number => [], undef ); value ( source => [], 'fubar' ); tokenize( '/$x{$y{z}}/' ); count ( 5 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x{$y{z}}' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); { # The navigation tests get done in their own local scope so that all # the object references we have held go away when we are done. parse ( '/ ( 1 2(?#comment)) /x' ); value ( failures => [], 0 ); value ( errstr => [], undef ); class ( 'PPIx::Regexp' ); value ( elements => [], 3 ); choose ( first_element => [] ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( last_element => [] ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'x' ); choose ( tokens => [] ); count ( 13 ); navigate( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '2' ); my $lit1 = choose( find_first => 'Token::Literal' ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '1' ); true ( significant => [] ); false ( whitespace => [] ); false ( comment => [] ); navigate( next_sibling => [] ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); false ( significant => [] ); true ( whitespace => [] ); false ( comment => [] ); my $lit2 = navigate( next_sibling => [] ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '2' ); navigate( previous_sibling => [] ); navigate( previous_sibling => [] ); equals ( $lit1, 'Two previouses undo two nexts' ); navigate( snext_sibling => [] ); equals ( $lit2, 'A snext gets us the next significant token' ); navigate( sprevious_sibling => [] ); equals ( $lit1, 'An sprevious gets us back' ); navigate( previous_sibling => [] ); equals ( undef, 'Nobody before the first literal' ); navigate( $lit2, next_sibling => [] ); class ( 'PPIx::Regexp::Token::Comment' ); content ( '(?#comment)' ); false ( significant => [] ); false ( whitespace => [] ); true ( comment => [] ); navigate( next_sibling => [] ); equals ( undef, 'Nobody after second whitespace' ); navigate( $lit2, snext_sibling => [] ); equals ( undef, 'Nobody significant after second literal' ); navigate( $lit1, sprevious_sibling => [] ); equals ( undef, 'Nobody significant before first literal' ); navigate( $lit1, parent => [] ); class ( 'PPIx::Regexp::Structure::Capture' ); my $top = navigate( top => [] ); class ( 'PPIx::Regexp' ); true ( ancestor_of => $lit1 ); true ( contains => $lit1 ); false ( ancestor_of => undef ); navigate( $lit1 ); true ( descendant_of => $top ); false ( descendant_of => $lit2 ); false ( ancestor_of => $lit2 ); false ( descendant_of => undef ); choose ( find => 'Token::Literal' ); count ( 2 ); navigate( -1 ); equals ( $lit2, 'The last literal is the second one' ); choose ( find_parents => 'Token::Literal' ); count ( 1 ); my $capt = navigate( 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); value ( elements => [], 7 ); value ( name => [], undef ); navigate( $capt, first_element => [] ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); navigate( $capt, last_element => [] ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); navigate( $capt, schildren => [] ); count ( 2 ); navigate( 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '2' ); choose ( find => sub { ref $_[1] eq 'PPIx::Regexp::Token::Literal' or return 0; $_[1]->content() eq '2' or return 0; return 1; } ); count ( 1 ); navigate( 0 ); equals ( $lit2, 'We found the second literal again' ); navigate( parent => [], schild => 1 ); equals ( $lit2, 'The second significant child is the second literal' ); navigate( parent => [], schild => -2 ); equals ( $lit1, 'The -2nd significant child is the first literal' ); choose ( previous_sibling => [] ); equals ( undef, 'The top-level object has no previous sibling' ); choose ( sprevious_sibling => [] ); equals ( undef, 'The top-level object has no significant previous sib' ); choose ( next_sibling => [] ); equals ( undef, 'The top-level object has no next sibling' ); choose ( snext_sibling => [] ); equals ( undef, 'The top-level object has no significant next sibling' ); choose ( find => [ {} ] ); equals ( undef, 'Can not find a hash reference' ); navigate( $lit2 ); value ( nav => [], [ child => [1], child => [0], child => [2] ] ); } SKIP: { # The cache tests get done in their own scope to ensure the objects # are destroyed. my $num_tests = 8; my $doc = PPI::Document->new( \'m/foo/smx' ) or skip( 'Failed to create PPI::Document', $num_tests ); my $m = $doc->find_first( 'PPI::Token::Regexp::Match' ) or skip( 'Failed to find PPI::Token::Regexp::Match', $num_tests ); my $o1 = PPIx::Regexp->new_from_cache( $m ); my $o2 = PPIx::Regexp->new_from_cache( $m ); equals( $o1, $o2, 'new_from_cache() same object' ); cache_count( 1 ); PPIx::Regexp->flush_cache( 42 ); # Anything not a PPIx::Regexp cache_count( 1 ); # Nothing happens my $o9 = PPIx::Regexp->new_from_cache( '/foo/' ); cache_count( 1 ); # Not cached. $o9->flush_cache(); cache_count( 1 ); # Not flushed, either. PPIx::Regexp->flush_cache(); cache_count(); $o1 = PPIx::Regexp->new_from_cache( $m ); cache_count( 1 ); $o1->flush_cache(); cache_count(); } SKIP: { # More cache tests, in their own scope not only to ensure object # destruction, but so $DISABLE_CACHE can be localized. local $PPIx::Regexp::DISABLE_CACHE = 1; my $num_tests = 2; my $doc = PPI::Document->new( \'m/foo/smx' ) or skip( 'Failed to create PPI::Document', $num_tests ); my $m = $doc->find_first( 'PPI::Token::Regexp::Match' ) or skip( 'Failed to find PPI::Token::Regexp::Match', $num_tests ); my $o1 = PPIx::Regexp->new_from_cache( $m ); my $o2 = PPIx::Regexp->new_from_cache( $m ); different( $o1, $o2, 'new_from_cache() same object, cache disabled' ); cache_count(); # Should still be nothing in cache. } tokenize( '/\\n\\04\\xff\\x{0c}\\N{LATIN SMALL LETTER E}\\N{U+61}/' ); count ( 10 ); choose ( 2 ); value ( ordinal => [], ord "\n" ); choose ( 3 ); value ( ordinal => [], ord "\04" ); choose ( 4 ); value ( ordinal => [], ord "\xff" ); choose ( 5 ); value ( ordinal => [], ord "\x{0c}" ); SKIP: { $have_charnames or skip( "unable to load charnames::vianame", 1 ); choose ( 6 ); value ( ordinal => [], ord 'e' ); } choose ( 7 ); value ( ordinal => [], ord 'a' ); tokenize( 's/\\b/\\b/' ); count ( 7 ); choose ( 4 ); value ( ordinal => [], ord "\b" ); tokenize( '//smx' ); count ( 4 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'smx' ); true ( asserts => 's' ); true ( asserts => 'm' ); true ( asserts => 'x' ); false ( negates => 'i' ); tokenize( '//r' ); count ( 4 ); choose ( 3 ); content ( 'r' ); true ( asserts => 'r' ); value ( match_semantics => [], undef ); value ( perl_version_introduced => [], 5.013002 ); tokenize( '/(?^:foo)/' ); count ( 10 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?^:' ); true ( asserts => 'd' ); false ( asserts => 'l' ); false ( asserts => 'u' ); true ( negates => 'i' ); true ( negates => 's' ); true ( negates => 'm' ); true ( negates => 'x' ); value ( match_semantics => [], 'd' ); value ( perl_version_introduced => [], 5.013006 ); tokenize( '/(?^l:foo)/' ); count ( 10 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '?^l:' ); false ( asserts => 'd' ); true ( asserts => 'l' ); false ( asserts => 'u' ); value ( match_semantics => [], 'l' ); value ( perl_version_introduced => [], 5.013006 ); tokenize( 'qr/foo{3}/' ); count ( 10 ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); false ( can_be_quantified => [] ); true ( is_quantifier => [] ); tokenize( 'qr/foo{3,}/' ); count ( 11 ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); false ( can_be_quantified => [] ); true ( is_quantifier => [] ); tokenize( 'qr/foo{3,5}/' ); count ( 12 ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); false ( can_be_quantified => [] ); true ( is_quantifier => [] ); tokenize( 'qr/foo{,3}/' ); count ( 11 ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); tokenize( '/{}/' ); count ( 6 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); tokenize( '/x{}/' ); count ( 7 ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '}' ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); tokenize( '/{2}/' ); count ( 7 ); choose ( 4 ); content ( '}' ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); tokenize( '/\\1?\\g{-1}*\\k{1,3}+/' ); count ( 15 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); value ( perl_version_introduced => [], MINIMUM_PERL ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{-1}' ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); value ( perl_version_introduced => [], '5.009005' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\k' ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); value ( perl_version_introduced => [], '5.009005' ); tokenize( '/\\\\d{3,5}+.*?/' ); count ( 15 ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); value ( perl_version_introduced => [], '5.009005' ); choose ( 12 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '?' ); value ( perl_version_introduced => [], MINIMUM_PERL ); tokenize( '/(?bar)/' ); count ( 10 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); value ( name => [], 'foo' ); value ( perl_version_introduced => [], '5.009005' ); tokenize( '/(?\'for\'bar)/' ); count ( 10 ); choose ( 3 ); value ( name => [], 'for' ); value ( perl_version_introduced => [], '5.009005' ); tokenize( '/(?Pbar)/' ); count ( 10 ); choose ( 3 ); value ( name => [], 'fur' ); value ( perl_version_introduced => [], '5.009005' ); tokenize( '/(*PRUNE:foo)x/' ); count ( 6 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Backtrack' ); content ( '(*PRUNE:foo)' ); value ( perl_version_introduced => [], '5.009005' ); tokenize( 's/\\bfoo\\Kbar/baz/' ); count ( 16 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\b' ); value ( perl_version_introduced => [], MINIMUM_PERL ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Assertion' ); content ( '\\K' ); value ( perl_version_introduced => [], '5.009005' ); tokenize( '/(*PRUNE:foo)x/' ); count ( 6 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Backtrack' ); content ( '(*PRUNE:foo)' ); value ( perl_version_introduced => [], '5.009005' ); tokenize( '/(?|(foo))/' ); count ( 12 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::BranchReset' ); content ( '?|' ); value ( perl_version_introduced => [], '5.009005' ); parse ( '/[a-z]/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( regular_expression => [] ); true ( interpolates => [] ); choose ( find_first => 'PPIx::Regexp::Structure::CharClass' ); class ( 'PPIx::Regexp::Structure::CharClass' ); false ( negated => [] ); parse ( 'm\'[^a-z]\'' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( regular_expression => [] ); false ( interpolates => [] ); choose ( find_first => 'PPIx::Regexp::Structure::CharClass' ); class ( 'PPIx::Regexp::Structure::CharClass' ); true ( negated => [] ); parse ( '/(?|(?foo(wah))|(bar))(hoo)/' ); value ( failures => [], 0 ); value ( max_capture_number => [], 3 ); value ( capture_names => [], [ 'baz' ] ); value ( perl_version_introduced => [], '5.009005' ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::BranchReset' ); count ( 3 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::BranchReset' ); content ( '?|' ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Structure::NamedCapture' ); count ( 4 ); value ( number => [], 1 ); value ( name => [], 'baz' ); choose ( child => 1, child => 0, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); content ( '?' ); choose ( child => 1, child => 0, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0, child => 3 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 3 ); value ( number => [], 2 ); choose ( child => 1, child => 0, child => 0, child => 3, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 0, child => 3, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, child => 0, child => 3, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 3 ); value ( number => [], 1 ); choose ( child => 1, child => 0, child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 2, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 3 ); value ( number => [], 3 ); choose ( child => 1, child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); parse ( 's/(foo)/${1}bar/g' ); class ( 'PPIx::Regexp' ); value ( failures => [], 0 ); value ( max_capture_number => [], 1 ); value ( capture_names => [], [] ); value ( perl_version_introduced => [], MINIMUM_PERL ); count ( 4 ); choose ( type => 0 ); content ( 's' ); choose ( regular_expression => [] ); content ( '/(foo)/' ); choose ( replacement => [] ); content ( '${1}bar/' ); choose ( modifier => [] ); content ( 'g' ); tokenize( '/((((((((((x))))))))))\\10/' ); count ( 26 ); choose ( 23 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\10' ); parse ( '/((((((((((x))))))))))\\10/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\10' ); tokenize( '/(((((((((x)))))))))\\10/' ); count ( 24 ); choose ( 21 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\10' ); parse ( '/(((((((((x)))))))))\\10/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\10' ); parse ( '/(x)\\1/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\1' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 1 ); parse ( '/(x)\\g1/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g1' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 1 ); parse ( '/(x)\\g-1/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => 0 ); class ( undef ); content ( undef ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g-1' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], -1 ); parse ( '/(x)\\g{1}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{1}' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 1 ); parse ( '/(x)\\g{-1}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{-1}' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], -1 ); parse ( '/(?\d+)\\g{foo}/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\g{foo}' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'foo' ); value ( number => [], undef ); parse ( '/(?)\\k/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\k' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'foo' ); value ( number => [], undef ); parse ( '/(?\d+)\\k\'foo\'/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '\\k\'foo\'' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'foo' ); value ( number => [], undef ); parse ( '/(?\d+)(?P=foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Backreference' ); content ( '(?P=foo)' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'foo' ); value ( number => [], undef ); parse ( '/(?1)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?1)' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 1 ); parse ( '/(x)(?-1)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 2 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?-1)' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], -1 ); parse ( '/(x)(?+1)(y)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?+1)' ); value ( absolute => [], 2 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], '+1' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Structure::Capture' ); parse ( '/(?R)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?R)' ); value ( absolute => [], 0 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 0 ); parse ( '/(?&foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?&foo)' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'foo' ); value ( number => [], undef ); parse ( '/(?P>foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Recursion' ); content ( '(?P>foo)' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'foo' ); value ( number => [], undef ); parse ( '/(?(1)foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); value ( perl_version_introduced => [], '5.005' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(1)' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 1 ); parse ( '/(?(R1)foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); value ( perl_version_introduced => [], '5.009005' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(R1)' ); value ( absolute => [], 1 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 1 ); parse ( '/(?()foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); value ( perl_version_introduced => [], '5.009005' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '()' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'bar' ); value ( number => [], undef ); parse ( '/(?(\'bar\')foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); value ( perl_version_introduced => [], '5.009005' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(\'bar\')' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'bar' ); value ( number => [], undef ); parse ( '/(?(R&bar)foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); value ( perl_version_introduced => [], '5.009005' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(R&bar)' ); value ( absolute => [], undef ); true ( is_named => [] ); value ( name => [], 'bar' ); value ( number => [], undef ); parse ( '/(?(DEFINE)foo)/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Switch' ); count ( 4 ); value ( perl_version_introduced => [], '5.009005' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Condition' ); content ( '(DEFINE)' ); value ( absolute => [], 0 ); false ( is_named => [] ); value ( name => [], undef ); value ( number => [], 0 ); tokenize( '/(?p{ code })/' ); count ( 8 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); value ( perl_version_removed => [], undef ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?p' ); value ( perl_version_removed => [], '5.009005' ); parse ( '/(?p{ code })/' ); value ( failures => [], 0); class ( 'PPIx::Regexp' ); value ( perl_version_removed => [], '5.009005' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); value ( perl_version_removed => [], undef ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); value ( perl_version_removed => [], '5.009005' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Code' ); count ( 1 ); value ( perl_version_removed => [], '5.009005' ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); value ( perl_version_removed => [], undef ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Code' ); content ( '?p' ); value ( perl_version_removed => [], '5.009005' ); parse ( 'qr{foo}smx' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); choose ( regular_expression => [] ); class ( 'PPIx::Regexp::Structure::Regexp' ); value ( delimiters => [], '{}' ); choose ( top => [] ); class ( 'PPIx::Regexp' ); value ( delimiters => [], '{}' ); value ( delimiters => 1, undef ); parse ( 's[bar]smx' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); choose ( regular_expression => [] ); class ( 'PPIx::Regexp::Structure::Regexp' ); value ( delimiters => [], '<>' ); choose ( top => [], replacement => [] ); class ( 'PPIx::Regexp::Structure::Replacement' ); value ( delimiters => [], '[]' ); choose ( top => [] ); class ( 'PPIx::Regexp' ); value ( delimiters => 0, '<>' ); value ( delimiters => 1, '[]' ); parse ( 's/foo/bar/smx' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); value ( delimiters => 0, '//' ); value ( delimiters => 1, '//' ); tokenize( '/foo/', encoding => 'utf8' ); value ( failures => [], 0 ); count ( 7 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); tokenize( 'm/\\N\\n/' ); count ( 6 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\N' ); value ( perl_version_introduced => [], '5.011' ); value ( perl_version_removed => [], undef ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\n' ); value ( perl_version_introduced => [], MINIMUM_PERL ); value ( perl_version_removed => [], undef ); tokenize( '/\\p{ Match = lo-ose }/' ); count ( 5 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\p{ Match = lo-ose }' ); value ( perl_version_introduced => [], '5.006001' ); value ( perl_version_removed => [], undef ); tokenize( '/\\pL/' ); count ( 5 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\pL' ); value ( perl_version_introduced => [], '5.006001' ); value ( perl_version_removed => [], undef ); parse ( 'm{)}smx' ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); value ( delimiters => 0, '{}' ); parse ( 's/(\\d+)/roman($1)/ge' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 4 ); value ( perl_version_introduced => [], '5.000' ); value ( perl_version_removed => [], undef ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( 'roman($1)' ); value ( perl_version_introduced => [], '5.000' ); value ( perl_version_removed => [], undef ); tokenize( '/${foo}bar/' ); count ( 8 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '${foo}' ); ppi ( '$foo' ); { parse ( 's/x/$1/e' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '$1' ); value ( ppi => [], PPI::Document->new( \'$1' ) ); my $doc1 = result(); value ( ppi => [], PPI::Document->new( \'$1' ) ); my $doc2 = result(); cmp_ok( refaddr( $doc1 ), '==', refaddr( $doc2 ), 'Ensure we get back the same object from both calls to ppi()' ); } ##tokenize( '/[[:lower:]]/' ); ##count ( 7 ); ##choose ( 3 ); ##class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); ##content ( '[:lower:]' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##true ( is_case_sensitive => [] ); ## ##parse ( '/[[:lower:]]/' ); ##value ( failures => [], 0 ); ##class ( 'PPIx::Regexp' ); ##count ( 3 ); ##choose ( child => 1 ); ##class ( 'PPIx::Regexp::Structure::Regexp' ); ##count ( 1 ); ##choose ( child => 1, child => 0 ); ##class ( 'PPIx::Regexp::Structure::CharClass' ); ##count ( 1 ); ##choose ( child => 1, child => 0, child => 0 ); ##class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); ##content ( '[:lower:]' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##true ( is_case_sensitive => [] ); ## ##tokenize( '/[[:alpha:]]/' ); ##count ( 7 ); ##choose ( 3 ); ##class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); ##content ( '[:alpha:]' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##false ( is_case_sensitive => [] ); ## ##parse ( '/[[:alpha:]]/' ); ##value ( failures => [], 0 ); ##class ( 'PPIx::Regexp' ); ##count ( 3 ); ##choose ( child => 1 ); ##class ( 'PPIx::Regexp::Structure::Regexp' ); ##count ( 1 ); ##choose ( child => 1, child => 0 ); ##class ( 'PPIx::Regexp::Structure::CharClass' ); ##count ( 1 ); ##choose ( child => 1, child => 0, child => 0 ); ##class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); ##content ( '[:alpha:]' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##false ( is_case_sensitive => [] ); ## ##tokenize( '/\\p{Lower}/' ); ##count ( 5 ); ##choose ( 2 ); ##class ( 'PPIx::Regexp::Token::CharClass::Simple' ); ##content ( '\\p{Lower}' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##true ( is_case_sensitive => [] ); ## ##parse ( '/\\p{Lower}/' ); ##value ( failures => [], 0 ); ##class ( 'PPIx::Regexp' ); ##count ( 3 ); ##choose ( child => 1 ); ##class ( 'PPIx::Regexp::Structure::Regexp' ); ##count ( 1 ); ##choose ( child => 1, child => 0 ); ##class ( 'PPIx::Regexp::Token::CharClass::Simple' ); ##content ( '\\p{Lower}' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##true ( is_case_sensitive => [] ); ## ##tokenize( '/\\p{Alpha}/' ); ##count ( 5 ); ##choose ( 2 ); ##class ( 'PPIx::Regexp::Token::CharClass::Simple' ); ##content ( '\\p{Alpha}' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##false ( is_case_sensitive => [] ); ## ##parse ( '/\\p{Alpha}/' ); ##value ( failures => [], 0 ); ##class ( 'PPIx::Regexp' ); ##count ( 3 ); ##choose ( child => 1 ); ##class ( 'PPIx::Regexp::Structure::Regexp' ); ##count ( 1 ); ##choose ( child => 1, start => [] ); ##count ( 1 ); ##choose ( child => 1, child => 0 ); ##class ( 'PPIx::Regexp::Token::CharClass::Simple' ); ##content ( '\\p{Alpha}' ); ##true ( significant => [] ); ##true ( can_be_quantified => [] ); ##false ( is_quantifier => [] ); ##false ( is_case_sensitive => [] ); parse ( '/ . /' ); false ( modifier_asserted => 'u' ); false ( modifier_asserted => 'x' ); parse ( '/ . /', default_modifiers => [ 'smxu' ] ); true ( modifier_asserted => 'u' ); false ( modifier_asserted => 'l' ); true ( modifier_asserted => 'x' ); parse ( '/ . /', default_modifiers => [ 'smxu', '-u' ] ); false ( modifier_asserted => 'u' ); false ( modifier_asserted => 'l' ); true ( modifier_asserted => 'x' ); # This to be sure we recognize 'aa' when consecutive. parse ( '/ . /aasmx' ); value ( failures => [], 0 ); true ( modifier_asserted => 'aa' ); false ( modifier_asserted => 'a' ); # Bug reported by Anonymous Monk. /aia is equivalent to /aai parse ( '/ . /asmxa' ); value ( failures => [], 0 ); true ( modifier_asserted => 'aa' ); false ( modifier_asserted => 'a' ); # Wishlist by Anonymous Monk to know what modifiers were asserted where. parse ( '/foo/i' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); true ( modifier_asserted => 'i' ); parse ( '/(?i)foo/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 4 ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); true ( modifier_asserted => 'i' ); parse ( '/(?i:foo)/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 3 ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); true ( modifier_asserted => 'i' ); parse ( '/foo/', default_modifiers => [ 'i' ] ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); true ( modifier_asserted => 'i' ); parse ( '/(?-i:foo)/i' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Modifier' ); count ( 3 ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); false ( modifier_asserted => 'i' ); # End of wishlist by Anonymous Monk to know what modifiers were asserted where. # Handle leading and trailing white space parse ( ' /foo/ ' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 5 ); value ( delimiters => [], '//' ); # The purpose of these choose ( modifier => [] ); # tests is to ensure class ( 'PPIx::Regexp::Token::Modifier' ); # that the significant value ( content => [], '' ); # parts of the regexp choose ( regular_expression => [] ); # can still be found if class ( 'PPIx::Regexp::Structure::Regexp' ); # we introduce leading choose ( type => 0 ); # and trailing white class ( 'PPIx::Regexp::Token::Structure' ); # space value ( content => [], '' ); # ... choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 2, start => [] ); count ( 1 ); choose ( child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, type => [] ); count ( 0 ); choose ( child => 2, finish => [] ); count ( 1 ); choose ( child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 2, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); choose ( child => 4 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); # RT #82140: incorrect parsing of (\?|...) - Alexandr Ciornii tokenize( '/(\\?|I)/' ); value ( failures => [], 0 ); count ( 9 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\?' ); tokenize( '?(\\?|I)?' ); value ( failures => [], 0 ); count ( 8 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::BranchReset' ); content ( '\\?|' ); # RT #82140: incorrect parsing of (\?>...) - Alexandr Ciornii tokenize( '/(\\?>I)/' ); value ( failures => [], 0 ); count ( 9 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\?' ); tokenize( '?(\\?>I)?' ); value ( failures => [], 0 ); count ( 8 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Subexpression' ); content ( '\\?>' ); # RT #82140: incorrect parsing of (\?:...) - Alexandr Ciornii tokenize( '/(\\?:I)/' ); value ( failures => [], 0 ); count ( 9 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\?' ); tokenize( '?(\\?:I)?' ); value ( failures => [], 0 ); count ( 8 ); choose ( 3 ); class ( 'PPIx::Regexp::Token::GroupType::Modifier' ); content ( '\\?:' ); # RT 91798: non-breaking space should not be whitespace - Nobuo Kumagai tokenize( "/\240/x" ); value ( failures => [], 0 ); count ( 5 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\240" ); note '/ee should parse like /e'; tokenize( 's/foo/bar(42)/ee' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( 's' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Code' ); content ( 'bar(42)' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( 'ee' ); # RT 107331 - Bogus trailing characters should cause error - Klaus Rindfrey parse ( '/foo/|' ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 4 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'f' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'o' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); choose ( child => 3 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '|' ); error ( 'Trailing characters after expression' ); choose ( 'modifier' => [] ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # As of Perl 5.23.4, only space and horizontal tab can be parsed as # whitespace inside a bracketed character class inside an extended # bracketed character class. tokenize( "/(?[ [\f] ])/" ); count ( 11 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(?[' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( "\f" ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Whitespace' ); content ( ' ' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '])' ); choose ( 9 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 10 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # Ensure that the error gets cleared when a PPIx::Regexp::Token::Unknown # gets reblessed into something useful. parse ( '/{?+}/' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Quantifier' ); content ( '?' ); error ( undef ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Token::Greediness' ); content ( '+' ); error ( undef ); # \U and friends are still metacharacters inside \Q tokenize( '/\\Q\\Ux\\Ey/' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\Q' ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\U' ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'x' ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Control' ); content ( '\\E' ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'y' ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # Need to report an error if the switch condition can not be deciphered. parse ( '/(?([w]))/' ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::Unknown' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, type => [] ); count ( 1 ); choose ( child => 1, child => 0, type => 0 ); class ( 'PPIx::Regexp::Token::GroupType::Switch' ); content ( '?' ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Structure::Capture' ); count ( 1 ); choose ( child => 1, child => 0, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, child => 0, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, child => 0, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 0, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'w' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # Make sure we do not prematurely end an extended bracketed character # class if we encounter a bracketed character class followed immediately # by the end of a parenthesized group (e.g. in '(?[([x])])' the extended # class should end at the end of the string). parse ( '/(?[(\\w-[[:lower:]])|\\p{Greek}])|[^a-z]/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 3 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::RegexSet' ); count ( 3 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(?[' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '])' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Structure' ); count ( 3 ); choose ( child => 1, child => 0, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '(' ); choose ( child => 1, child => 0, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ')' ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\w' ); choose ( child => 1, child => 0, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( child => 1, child => 0, child => 0, child => 2 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, child => 0, child => 2, start => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, child => 0, child => 2, type => [] ); count ( 0 ); choose ( child => 1, child => 0, child => 0, child => 2, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, child => 0, child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0, child => 2, child => 0 ); class ( 'PPIx::Regexp::Token::CharClass::POSIX' ); content ( '[:lower:]' ); choose ( child => 1, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( child => 1, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::CharClass::Simple' ); content ( '\\p{Greek}' ); choose ( child => 1, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '|' ); choose ( child => 1, child => 2 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 2, start => [] ); count ( 1 ); choose ( child => 1, child => 2, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 2, type => [] ); count ( 1 ); choose ( child => 1, child => 2, type => 0 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '^' ); choose ( child => 1, child => 2, finish => [] ); count ( 1 ); choose ( child => 1, child => 2, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 2, child => 0 ); class ( 'PPIx::Regexp::Node::Range' ); count ( 3 ); choose ( child => 1, child => 2, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); choose ( child => 1, child => 2, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); choose ( child => 1, child => 2, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); # Make sure we record the correct number of captures in the presence of # the /n qualifier. note 'Correct number of captures in presence of /n qualifier'; parse ( '/(foo)/n' ); value ( max_capture_number => [], 0 ); parse ( '/(?foo)/n' ); value ( max_capture_number => [], 1 ); # ?foo? without a specific type has been removed as of 5.21.1. These # would be in t/version.t except that the limit is not on a single # token but on the combination of empty type and question mark # delimiters. note '?foo? without explicit type is removed in 5.21.1'; parse ( '?foo?' ); value ( perl_version_removed => [], 5.021001 ); parse ( 'm?foo?' ); value ( perl_version_removed => [], undef ); # postderef note 'postderef was added experimentally in 5.19.5'; tokenize( '/$x->$*foo/', postderef => 1 ); count ( 8 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x->$*' ); tokenize( '/$x->$#*foo/', postderef => 1 ); count ( 8 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x->$#*' ); tokenize( '/$x->@*foo/', postderef => 1 ); count ( 8 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x->@*' ); tokenize( '/$x->@[1,2]/', postderef => 1 ); count ( 5 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Interpolation' ); content ( '$x->@[1,2]' ); tokenize( 's/x/$x->%{foo,bar}/e', postderef => 1 ); count ( 7 ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Code' ); content ( '$x->%{foo,bar}' ); note 'Make sure \Q stacks with \U, \L and \F'; tokenize( '/\\Qx\\Uy\\E\\w\\E/' ); count ( 11 ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( '\\w' ); note 'use re qw{ strict }'; tokenize( '/\\N{}/', strict => 1 ); count ( 5 ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Unknown' ); content ( '\\N{}' ); error ( 'Empty Unicode character name prohibited by "use re \'strict\'"' ); value ( perl_version_introduced => [], '5.023008' ); value ( perl_version_removed => [], '5.027001' ); parse ( '/[A-z]/', strict => 1 ); value ( failures => [], 1 ); class ( 'PPIx::Regexp' ); count ( 3 ); value ( perl_version_introduced => [], '5.023008' ); value ( perl_version_removed => [], undef ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Node::Unknown' ); count ( 3 ); error ( 'Non-portable range ends prohibited by "use re \'strict\'"' ); value ( perl_version_introduced => [], '5.023008' ); value ( perl_version_removed => [], undef ); note 'accepts_perl(), requirements_for_perl()'; parse ( '/x/' ); value ( accepts_perl => [ '5.000' ], 1 ); value ( accepts_perl => [ '5.010001' ], 1 ); value ( requirements_for_perl => [], '5.000 <= $]' ); parse ( '/x/a' ); value ( accepts_perl => [ '5.000' ], 0 ); value ( accepts_perl => [ '5.010001' ], 0 ); value ( accepts_perl => [ '5.013010' ], 1 ); value ( accepts_perl => [ '5.014' ], 1 ); value ( requirements_for_perl => [], '5.013010 <= $]' ); parse ( '/x{/' ); value ( accepts_perl => [ '5.000' ], 1 ); value ( accepts_perl => [ '5.010001' ], 1 ); value ( accepts_perl => [ '5.025000' ], 1 ); value ( accepts_perl => [ '5.025001' ], 0 ); value ( accepts_perl => [ '5.027000' ], 0 ); value ( accepts_perl => [ '5.027001' ], 1 ); value ( requirements_for_perl => [], '5.000 <= $] < 5.025001 || 5.027001 <= $]' ); { my $re = '/ [f g] o o b a (?#comment) r /'; parse ( $re ); value ( scontent => [], '/ [f g] o o b a r /' ); parse ( $re, default_modifiers => [ qw{ x } ] ); value ( scontent => [], '/[f g]oobar/' ); parse ( $re, default_modifiers => [ qw{ xx } ] ); value ( scontent => [], '/[fg]oobar/' ); } SKIP: { $is_ascii or skip( 'Non-ASCII machines will have different ordinal values', 10, ); note 'Ordinals'; tokenize( '/foo/', '--notokens' ); dump_result( ordinal => 1, tokens => 1, <<'EOD', q ); PPIx::Regexp::Token::Structure '' PPIx::Regexp::Token::Delimiter '/' PPIx::Regexp::Token::Literal 'f' 0x66 PPIx::Regexp::Token::Literal 'o' 0x6f PPIx::Regexp::Token::Literal 'o' 0x6f PPIx::Regexp::Token::Delimiter '/' PPIx::Regexp::Token::Modifier '' EOD parse ( '/(foo[a-z\\d])/x' ); dump_result( verbose => 1, <<'EOD', q ); PPIx::Regexp failures=0 max_capture_number=1 PPIx::Regexp::Token::Structure '' significant PPIx::Regexp::Structure::Regexp / ... / max_capture_number=1 PPIx::Regexp::Structure::Capture ( ... ) number=1 name=undef can_be_quantified PPIx::Regexp::Token::Literal 'f' 0x66 significant can_be_quantified PPIx::Regexp::Token::Literal 'o' 0x6f significant can_be_quantified PPIx::Regexp::Token::Literal 'o' 0x6f significant can_be_quantified PPIx::Regexp::Structure::CharClass [ ... ] can_be_quantified PPIx::Regexp::Node::Range PPIx::Regexp::Token::Literal 'a' 0x61 significant can_be_quantified PPIx::Regexp::Token::Operator '-' significant can_be_quantified PPIx::Regexp::Token::Literal 'z' 0x7a significant can_be_quantified PPIx::Regexp::Token::CharClass::Simple '\\d' significant can_be_quantified PPIx::Regexp::Token::Modifier 'x' significant x EOD parse ( '/(?\\d+)/' ); dump_result( perl_version => 1, <<'EOD', q\\d+)/'> ); PPIx::Regexp failures=0 5.009005 <= $] PPIx::Regexp::Token::Structure '' 5.000 <= $] PPIx::Regexp::Structure::Regexp / ... / 5.009005 <= $] PPIx::Regexp::Structure::NamedCapture (? ... ) 5.009005 <= $] PPIx::Regexp::Token::CharClass::Simple '\\d' 5.000 <= $] PPIx::Regexp::Token::Quantifier '+' 5.000 <= $] PPIx::Regexp::Token::Modifier '' 5.000 <= $] EOD tokenize( '/[a-z]/', '--notokens' ); dump_result( test => 1, verbose => 1, tokens => 1, <<'EOD', q ); tokenize( '/[a-z]/' ); count ( 9 ); choose ( 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); true ( significant => [] ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 1 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); true ( significant => [] ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 2 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); true ( significant => [] ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 3 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 4 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 5 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 6 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 7 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); true ( significant => [] ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( 8 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); true ( significant => [] ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); EOD parse ( '/[a-z]/' ); dump_result( test => 1, verbose => 1, <<'EOD', q ); parse ( '/[a-z]/' ); value ( failures => [], 0 ); class ( 'PPIx::Regexp' ); count ( 3 ); choose ( child => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '' ); true ( significant => [] ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( child => 1 ); class ( 'PPIx::Regexp::Structure::Regexp' ); count ( 1 ); choose ( child => 1, start => [] ); count ( 1 ); choose ( child => 1, start => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, type => [] ); count ( 0 ); choose ( child => 1, finish => [] ); count ( 1 ); choose ( child => 1, finish => 0 ); class ( 'PPIx::Regexp::Token::Delimiter' ); content ( '/' ); choose ( child => 1, child => 0 ); class ( 'PPIx::Regexp::Structure::CharClass' ); count ( 1 ); choose ( child => 1, child => 0, start => [] ); count ( 1 ); choose ( child => 1, child => 0, start => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( '[' ); choose ( child => 1, child => 0, type => [] ); count ( 0 ); choose ( child => 1, child => 0, finish => [] ); count ( 1 ); choose ( child => 1, child => 0, finish => 0 ); class ( 'PPIx::Regexp::Token::Structure' ); content ( ']' ); choose ( child => 1, child => 0, child => 0 ); class ( 'PPIx::Regexp::Node::Range' ); count ( 3 ); choose ( child => 1, child => 0, child => 0, child => 0 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'a' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( child => 1, child => 0, child => 0, child => 1 ); class ( 'PPIx::Regexp::Token::Operator' ); content ( '-' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( child => 1, child => 0, child => 0, child => 2 ); class ( 'PPIx::Regexp::Token::Literal' ); content ( 'z' ); true ( significant => [] ); true ( can_be_quantified => [] ); false ( is_quantifier => [] ); choose ( child => 2 ); class ( 'PPIx::Regexp::Token::Modifier' ); content ( '' ); true ( significant => [] ); false ( can_be_quantified => [] ); false ( is_quantifier => [] ); EOD } finis (); done_testing; 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/t/version.t000444000765000024 11606613237102475 15206 0ustar00tomstaff000000000000# This test instantiates tokens directly rather than through the # tokenizer. It is up to the author of the test to be sure that the # the contents of each token are consistent with its class. There is # also the risk that tokens instantiated directly may be set up # differently than theoretically-equivalent tokens generated by the # tokenizer, in cases where __PPIX_TOKEN__recognize() is used. # # Caveat Auctor. package main; use 5.006; use strict; use warnings; use Test::More 0.88; our $REPORT; # True to report rather than test. # If $REPORT is true, you get instead of a test a CSV-formatted report # of the syntax elements and the versions they were introduced and # retracted. Named arguments to the routines have been added to support # the report -- perhaps too many of them. All are optional. They are: # note => Text describing the thing being reported on. This is # described further in the details of the report. # text => The text of the thing reported on. If applied to the class # it is a sprintf template. The default is the content of the # token. # report => false to suppress the report. If applied to the class it # is a default for all tokens in that class. # The columns of the report are: # Kind => The kind of syntax element. This is the 'note' argument to # the class() subroutine, and defaults to the class name. # Token => The syntax element itself. This is the 'text' argument of # the token() or class() subroutines (the latter suitably # processed), defaulting to the actual content of the syntax # element. # Descr => The description of the syntax element. This is the 'note' # argument of the token() subroutine, defaulting to the empty # string. # Introduced => The version of Perl in which the element was # introduced, from the perl_version_introduced() method of the # token. Since I have not researched Perl 4, and I have no # access to Perls earlier than 5.3, anything in 5.3 is assumed # willy-nilly to be in Perl 5.0. # Ref => The source of the version introduced, if known. Typically a # Perl documentation reference. If a reference other than # perl?*delta, the Perl version of the documentation is # prefaced, and the version is inferred from the fact that the # previous version of the document did not refer to the feature. # The default is the empty string. # Removed => The version of Perl in which the element was removed. # The default is '', indicating that the element is still in # Perl. # Ref => The source of the version removed, if known, and if the # element has in fact been removed. # # One way to use this is # $ perl -e '$REPORT = 1; do "t/version.t";' # Trailing empty fields are removed. use PPIx::Regexp::Constant qw{ COOKIE_CLASS COOKIE_REGEX_SET MINIMUM_PERL }; use PPIx::Regexp::Tokenizer; sub class (@); sub finis (); sub method (@); sub token (@); class 'PPIx::Regexp::Token::Assertion', note => 'Assertion'; token '^', note => 'Matches beginning of string or after newline'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '$', note => 'Matches end of string or newline'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\b', note => 'Matches word/nonword boundary'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\B', note => 'Opposite of \b'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\A', note => 'Matches beginning of string'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\Z', note => 'Matches end of string, or newline before end'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\G', note => 'Matches at pos()'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\z', note => 'Matches end of string'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; token '\K', note => 'In s///, keep everything before the \K'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\b{gcb}', note => 'Assert grapheme cluster boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; token '\b{g}', note => 'Assert grapheme cluster boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; token '\b{lb}', note => 'Assert line boundary'; method perl_version_introduced => '5.023007', note => 'perl5237delta'; method perl_version_removed => undef; token '\b{wb}', note => 'Assert word boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; token '\b{sb}', note => 'Assert sentence boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; token '\B{gcb}', note => 'Assert no grapheme cluster boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; token '\B{g}', note => 'Assert no grapheme cluster boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; token '\B{lb}', note => 'Assert no line boundary'; method perl_version_introduced => '5.023007', note => 'perl5237delta'; method perl_version_removed => undef; token '\B{wb}', note => 'Assert no word boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; token '\B{sb}', note => 'Assert no sentence boundary'; method perl_version_introduced => '5.021009', note => 'perl5219delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Backreference', note => 'Back reference'; token '\1', note => 'Back reference to first capture group'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\g1', note => 'Back reference to first capture group'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\g{1}', note => 'Back reference to first capture group'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\g-1', note => 'Back reference to previous capture group'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '\g{-1}', note => 'Back reference to previous capture group'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\k', note => 'Back reference to named capture group'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token q{\k'foo'}, note => 'Back reference to named capture group'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(?P=foo)', note => 'Back reference to named capture group'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Backtrack', note => 'Back tracking control'; token '(*THEN)', note => 'Forces next alternation on failure'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '(*PRUNE)', note => 'Prevent backtracking past here on failure'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '(*MARK)', note => 'Name branches of alternation, target for (*SKIP)'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '(*SKIP)', note => 'Like (*PRUNE) but also discards match to this point'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '(*COMMIT)', note => 'Causes match failure when backtracked into on failure'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '(*FAIL)', note => 'Always fails, forcing backtrack'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '(*ACCEPT)', note => 'Causes match to succeed at the point of the (*ACCEPT)'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::CharClass::POSIX', note => 'POSIX character class'; token '[:alpha:]', note => 'Match alphabetic'; method perl_version_introduced => '5.006', note => 'perl56delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::CharClass::Simple', note => 'Character class'; token '.', note => 'Match any character'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\w', note => 'Match word character'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\W', note => 'Match non-word character'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\s', note => 'Match white-space character'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\S', note => 'Match non-white-space character'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\d', note => 'Match decimal digit'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\D', note => 'Match any character but a decimal digit'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\C', note => 'Match a single octet (removed in 5.23.0)'; method perl_version_introduced => '5.006'; method perl_version_removed => '5.023'; token '\X', note => 'Match a Unicode extended grapheme cluster'; method perl_version_introduced => '5.006', note => '5.6.0 perlre'; method perl_version_removed => undef; token '\p{Latin}', note => 'Match a character with the given Unicode property'; method perl_version_introduced => '5.006001', note => 'perl561delta'; method perl_version_removed => undef; token '\h', note => 'Match a horizontal-white-space character'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\H', note => 'Match a non-horizontal-white-space character'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\v', note => 'Match a vertical-white-space character'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\V', note => 'Match a non-vertical-white-space character'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\R', note => 'Match a generic new-line character'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token '\N', note => 'Match any character but a new-line character'; method perl_version_introduced => '5.011', note => 'perl5110delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Code', note => 'Code', report => 0; token '{foo}', note => 'Code'; method perl_version_introduced => '5.005'; # see ::GroupType::Code method perl_version_removed => undef; token '$x->&*', postderef => 1, note => 'Code with postderef'; method perl_version_introduced => '5.019005', note => 'perl5195delta'; method perl_version_removed => undef; token '$x->%{foo,bar}', postderef => 1, note => 'Code with postderef slice'; method perl_version_introduced => '5.019005', note => 'perl5195delta'; method perl_version_removed => undef; # The interesting version functionality is on # PPIx::Regexp::Token::GroupType::Code. class 'PPIx::Regexp::Token::Comment', note => 'Comment'; token '(?#foo)', note => 'Embedded comment'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '# foo', note => 'Extended comment, with /x'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Condition', note => 'Condition'; token '(1)', note => 'True if the first capture group matched'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; token '(R1)', note => 'True if recursing directly inside first capture group'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(R)', note => 'True if recursing'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '()', note => 'True if capture group matched'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token q{('foo')}, note => 'True if capture group matched'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(R&foo)', note => 'True if recursing directly inside capture group '; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(DEFINE)', note => 'Define a group to be recursed into'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Control', note => 'Interpolation control'; token '\l', note => 'Lowercase next character'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\u', note => 'Uppercase next character'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\L', note => 'Lowercase until \E'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\U', note => 'Uppercase until \E'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\F', note => 'Fold case until \E'; method perl_version_introduced => '5.015008'; method perl_version_removed => undef; token '\E', note => 'End of interpolation control'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\Q', note => 'Quote interpolated metacharacters until \E'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Delimiter', note => 'Delimiter', report => 0; token '/'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; class 'PPIx::Regexp::Token::Greediness', note => 'Greediness'; token '?', note => 'Match shortest string first'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '+', note => 'Match longest string and give nothing back'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; # PPIx::Regexp::Token::GroupType: see the individual subclasses, below. class 'PPIx::Regexp::Token::GroupType::Assertion', note => 'Assertion', text => '(%sregexp)'; token '?=', note => 'Positive lookahead'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '?!', note => 'Negative lookahead'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '?<=', note => 'Positive lookbehind'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; token '? 'Negative lookbehind'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::BranchReset', note => 'Branch reset'; token '?|', note => 'Re-use capture group numbers in branches of alternation', text => '(?|regexp|regexp...)'; method perl_version_introduced => '5.009005', note => '5.9.5 perlre'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::Code', note => 'Code', text => '(%s{code})'; token '?p', note => 'Function unknown'; method perl_version_introduced => '5.005', note => 'Undocumented that I can find'; method perl_version_removed => '5.009005', note => 'perl595delta'; token '?', note => 'Evaluate code. Always matches.'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; token '??', note => 'Evaluate code, use as regexp at this point'; method perl_version_introduced => '5.006', note => 'perl56delta (not in 5.5.4 perlre)'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::Modifier', note => 'Clustering', text => '(%sregexp)'; token '?:', note => 'Basic clustering'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '?i:', note => 'Cluster with case-independance'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; token '?i-x:', note => 'Cluster with case-independance but no extended syntax'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::Modifier', note => 'Modifiers', text => '(%s)', report => 0; token '?^i', note => 'Reassert defaults, case-independance'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; token '?d', note => 'Compile without locale or unicode_strings'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; token '?l', note => 'Compile with locale'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; token '?u', note => 'Compile with unicode_strings'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::NamedCapture', note => 'Named capture', text => '(%sregexp)'; token '?', note => 'Basic named capture'; method perl_version_introduced => '5.009005', note => 'perl595delta'; method perl_version_removed => undef; token q{?'foo'}, note => 'Named capture, quoted syntax'; method perl_version_introduced => '5.009005', note => '5.9.5 perlre'; method perl_version_removed => undef; token '?P', note => 'Named capture, PCRE/Python syntax'; method perl_version_introduced => '5.009005', note => '5.9.5 perlre'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::Subexpression', note => 'Subexpression', text => '(%sregexp)'; token '?>', note => 'Match subexpression without backtracking'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::Switch', note => 'Switch', report => 0; # See PPIx::Regexp::Token::Condition token '?'; method perl_version_introduced => '5.005'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Interpolation', note => 'Interpolation'; token '$foo', note => 'Interpolate the contents of $foo'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '$foo', cookie => COOKIE_REGEX_SET, note => 'Interpolation in regex set'; method perl_version_introduced => '5.017009', note => 'perl5179delta'; method perl_version_removed => undef; token '$x->@*', postderef => 1, note => 'Postfix deref'; method perl_version_introduced => '5.019005', note => 'perl5195delta'; method perl_version_removed => undef; token '$x->@[1,2]', postderef => 1, note => 'Postfix deref slice'; method perl_version_introduced => '5.019005', note => 'perl5195delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Literal', note => 'Literal'; token 'a', note => q{Letter 'a'}; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\b', note => 'Back space, in character class only'; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; token '\t', note => 'Horizontal tab'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\n', note => 'New line'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\r', note => 'Return'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\a', note => 'Alarm (bell)'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\e', note => 'Escape'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\033', note => 'Octal 33 = escape, classic'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\o{61}', note => q{Octal 61 = '1', new style}; method perl_version_introduced => '5.013003', note => 'perl5133delta'; method perl_version_removed => undef; token '\x1B', note => 'Hex 1b = escape, classic'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\x{1b}', note => 'Hex 1b = escape, new style'; method perl_version_introduced => '5.006', note => '5.6.0 perlre (not in perldelta)'; method perl_version_removed => undef; token '\c[', note => 'Control-[ = escape'; # ] method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '\N{LATIN SMALL LETTER P}', note => q{Letter 'p', by name}; method perl_version_introduced => '5.006001', note => 'perl561delta'; method perl_version_removed => undef; token '\N{U+32}', note => q{Digit '2', by Unicode code point}; method perl_version_introduced => '5.008', note => '5.8.0 charnames'; method perl_version_removed => undef; token '{', note => 'Initial unescaped literal left curly'; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; token '{', note => 'Unescaped literal left curly', previous => 1; method perl_version_introduced => MINIMUM_PERL; # method perl_version_removed => '5.025001'; note '/x{/ removed in 5.025001, re-added in 5.027001'; method perl_version_removed => undef; token '\s', class => 'PPIx::Regexp::Token::CharClass::Simple'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => '5.025001'; token '.', class => 'PPIx::Regexp::Token::CharClass::Simple'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; # Not removed yet token '\p{Latin}', class => 'PPIx::Regexp::Token::CharClass::Simple'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; # Not removed yet token '\P{Latin}', class => 'PPIx::Regexp::Token::CharClass::Simple'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; # Not removed yet token '^', class => 'PPIx::Regexp::Token::Assertion'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; require PPIx::Regexp::Structure::Assertion; token undef, class => 'PPIx::Regexp::Structure::Assertion'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; require PPIx::Regexp::Structure::CharClass; token undef, class => 'PPIx::Regexp::Structure::CharClass'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; # Not removed yet require PPIx::Regexp::Structure::RegexSet; token undef, class => 'PPIx::Regexp::Structure::RegexSet'; token '{', previous => 1; method perl_version_introduced => MINIMUM_PERL; method perl_version_removed => undef; # Not removed yet class 'PPIx::Regexp::Token::Modifier', note => 'Operator modifiers', text => '/%s'; token 'i', note => 'Case independent'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 's', note => 'Single-line'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'm', note => 'Multiple lines'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'x', note => 'Extended syntax'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'xx', note => 'Extended syntax eveb inside bracketed classes'; method perl_version_introduced => '5.025009', note => '5.25.9 perldelta'; method perl_version_removed => undef; token 'g', note => 'Global matching'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'o', note => 'Compile once'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'e', note => 'Replacement is expression'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'ee', note => 'Replacement is eval-ed expression'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'c', note => 'Do not reset pos() on failure (with /g)'; method perl_version_introduced => '5.004', note => '5.4.5 perlop'; method perl_version_removed => undef; token 'p', note => 'Populate ${^PREMATCH}, ${^MATCH}, and ${^POSTMATCH}'; method perl_version_introduced => '5.009005', note => '5.9.5 perlop'; method perl_version_removed => undef; token 'r', note => 'Return modified string from s///, leaving original unmodified'; method perl_version_introduced => '5.013002', note => 'perl5132delta'; method perl_version_removed => undef; token 'pi', report => 0; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token 'pir', report => 0; method perl_version_introduced => '5.013002'; method perl_version_removed => undef; token 'a', note => 'Match like /u, but restrict non-Unicode classes to ASCII'; method perl_version_introduced => '5.013010', note => 'perl51310delta'; method perl_version_removed => undef; token 'aa', note => 'Match like /a, and do not match ASCII and non-ASCII literals'; method perl_version_introduced => '5.013010', note => 'perl51310delta'; method perl_version_removed => undef; token 'd', note => 'Match using default (pre-5.13.10) semantics'; method perl_version_introduced => '5.013010', note => 'perl51310delta'; method perl_version_removed => undef; token 'l', note => 'Match using current locale semantics'; method perl_version_introduced => '5.013010', note => 'perl51310delta'; method perl_version_removed => undef; token 'u', note => 'Match using Unicode semantics'; method perl_version_introduced => '5.013010', note => 'perl51310delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Modifier', note => 'Embedded modifiers'; token '(?i)', note => 'Basic modifier (case-independence)'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '(?i-x)', note => 'Negated modifier (extended syntax)'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; token '(?^i)', note => 'Re-apply defaults, plus case-independence'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; token '(?a)', note => 'Embedded /a'; method perl_version_introduced => '5.013009', note => 'perl5139delta'; method perl_version_removed => undef; token '(?d)', note => 'Embedded /d'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; token '(?l)', note => 'Embedded /l'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; token '(?u)', note => 'Embedded /u'; method perl_version_introduced => '5.013006', note => 'perl5136delta'; method perl_version_removed => undef; token '(?aa)', note => 'Embedded /aa'; method perl_version_introduced => '5.013010', note => 'perl51310delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::NoOp', note => 'Does nothing'; token '\\N{}', note => 'Unicode character with empty name'; method perl_version_introduced => MINIMUM_PERL, note => 'perl5238delta (!)'; method perl_version_removed => '5.027001', note => 'perl5271delta'; class 'PPIx::Regexp::Token::Operator', note => 'Operator'; token '|', note => 'Alternation (outside character class)'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '^', cookie => COOKIE_CLASS, note => 'Character class inversion'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '-', cookie => COOKIE_REGEX_SET, note => 'Character range (inside character class)'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Quantifier', note => 'Quantifier'; token '*', note => 'Zero or more'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '+', note => 'One or more'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '?', note => 'Zero or one'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; # TODO the quantifier {m,n} gets covered, if at all, under # PPIx::Regexp::Token::Structure. class 'PPIx::Regexp::Token::Recursion', note => 'Recursion'; token '(?1)', note => 'Recurse to first capture'; method perl_version_introduced => '5.009005'; # perl595delta method perl_version_removed => undef; token '(?+1)', note => 'Recurse to next capture'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(?-1)', note => 'Recurse to previous capture'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(?R)', note => 'Recurse to beginning of pattern'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(?&foo)', note => 'Recurse to named capture '; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; token '(?P>foo)', note => 'Recurse to named capture , PCRE/Python syntax'; method perl_version_introduced => '5.009005'; method perl_version_removed => undef; # PPIx::Regexp::Token::Reference is the parent of # PPIx::Regexp::Token::Backreference, PPIx::Regexp::Token::Condition, # and PPIX::Regexp::Token::Recursion. It has no separate tests. class 'PPIx::Regexp::Token::Structure', report => 0; token '('; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token ')'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '['; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token ']'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '{'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Structure', note => 'Quantifier'; token '}', is_quantifier => 1, note => 'Explicit quantifier', text => '{n} or {n,m}'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Structure', note => 'Perl operator'; token 'm', note => 'Match', text => 'm//'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 's', note => 'Substitute', text => 's///'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token 'qr', note => 'Regexp constructor', text => 'qr{}'; method perl_version_introduced => '5.005', note => 'perl5005delta'; method perl_version_removed => undef; # TODO if the quantifier {m,n} gets forms that are only legal for # certain Perls, things may get sticky, but at the token level '}' is # the one marked as a quantifier, so here's the starting point. class 'PPIx::Regexp::Token::Whitespace', note => 'White space'; token ' ', note => 'Not significant under /x'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; # RT #91798. The following was implemented prematurely. What happened in # 5.17.9 was not the recognition of non-ASCII spaces, but the # requirement that they be escaped, so they could be recognized # eventually. # The non-ASCII white space was finally introduced in 5.21.1. if ( $] >= 5.008 ) { # The following eval is to hide the construct from Perl 5.6, which # does not understand \N{...}. token eval q<" \\N{U+0085}">, ## no critic (ProhibitStringyEval) note => 'Non-ASCII space'; method perl_version_introduced => '5.021001', note => 'perl5179delta'; method perl_version_removed => undef; } class 'PPIx::Regexp::Token::Structure', note => 'Regex set'; token '(?['; method perl_version_introduced => '5.017008', note => 'perl5178delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::Modifier', note => 'Non-capturing parens'; token 'n'; method perl_version_introduced => '5.021008', note => 'perl5218delta'; method perl_version_removed => undef; class 'PPIx::Regexp::Token::GroupType::Script_Run', note => 'All characters must be in same script'; token '+script_run:'; method perl_version_introduced => '5.027008', note => 'perl5278delta'; method perl_version_removed => undef; finis; my $context; my @report_info; BEGIN { $context = {}; } sub class (@) { my ( $class, %args ) = @_; $args{class} = $class; $context = undef; my $title = "require $class"; if ( eval "require $class; 1" ) { $context->{class} = \%args; $REPORT and return; @_ = ( $title ); goto &pass; } else { $REPORT and die $title; @_ = ( "$title: $@" ); goto &fail; } } sub _dor { # Because we do not require 5.010. my ( @args ) = @_; foreach my $arg ( @args ) { defined $arg and return $arg; } return undef; # Yes, I want this in array context. } { my $csv; sub _report { my ( @args ) = @_; if ( ! $csv ) { require Text::CSV; $csv = Text::CSV->new(); $csv->combine( 'Kind', 'Token', 'Descr', 'Introduced', 'Ref', 'Removed', 'Ref' ) or die 'Invalid CSV input: ', $csv->error_input(); print $csv->string(), "\n"; } $csv->combine( @args ) or die 'Invalid CSV input: ', $csv->error_input(); print $csv->string(), "\n"; return; } } sub finis () { $REPORT or goto &done_testing; foreach my $item ( @report_info ) { my @data = ( _dor( $item->{class}{note}, $item->{class}{class} ), _dor( $item->{token}{text}, $item->{token}{content} ), _dor( $item->{token}{note}, '' ), ); foreach my $method ( qw{ perl_version_introduced perl_version_removed } ) { if ( $item->{$method} ) { push @data, _dor( $item->{$method}{got}, '' ), _dor( $item->{$method}{note}, '' ); } else { push @data, '', ''; } } while ( @data && '' eq $data[-1] ) { pop @data; } _report( @data ); } return; } { my %annotate; BEGIN { %annotate = map { $_ => 1 } qw{ perl_version_introduced perl_version_removed }; } sub method (@) { my ( $method, @args ) = @_; my ( %info, $kind, $want ); if ( $annotate{$method} ) { $kind = $1; $want = shift @args; %info = @args; @args = (); } else { $want = pop @args; } SKIP: { defined $context->{object} or skip 'No object defined', 1; my $argtxt = @args ? ' ' . join( ', ', map { "'$_'" } @args ) . ' ' : ''; my $title; if ( defined $want ) { $title = "$method($argtxt) is '$want'"; } else { $title = "$method($argtxt) is undef"; } my $got; eval { $got = $context->{object}->$method( @args ); 1; } or do { $title .= ": $@"; chomp $title; $REPORT and die $title; @_ = ( $title ); goto &fail; }; $info{got} = $got; $context->{$method} = \%info; $REPORT and return; @_ = ( $got, $want, $title ); goto &is; } } } sub token (@) { my ( $content, %args ) = @_; SKIP: { defined $context->{class} or skip 'No class defined', 1; my $previous = $context->{object} or delete $args{previous}; $context = { class => $context->{class}, token => { content => $content, note => delete $args{note}, }, }; my $text = exists $args{text} ? delete $args{text} : exists $context->{class}{text} ? sprintf $context->{class}{text}, $content : undef; defined $text and $context->{token}{text} = $text; my $report = exists $args{report} ? delete $args{report} : exists $context->{class}{report} ? $context->{class}{report} : 1; $REPORT and $report and push @report_info, $context; my $class = defined $args{class} ? $args{class} : $context->{class}{class}; my $title = sprintf 'Instantiate %s with %s', $class, defined $content ? "'$content'" : '()'; $args{previous} and $title .= sprintf q< preceded by '%s'>, $previous->content(); if ( eval { my $tokenizer = PPIx::Regexp::Tokenizer->new( $content || '', postderef => $args{postderef}, ); if ( my $code = $class->can( '__make_group_type_matcher' ) ) { foreach my $matcher ( @{ $code->( $class )->{''} } ) { $tokenizer->find_regexp( $matcher ) and last; } } if ( my $cookie = delete $args{cookie} ) { $tokenizer->cookie( $cookie => sub { 1 } ); } my $obj = $class->__new( defined $content ? $content : (), $class->isa( 'PPIx::Regexp::Token' ) ? ( tokenizer => $tokenizer ) : (), ); if ( delete $args{previous} ) { require PPIx::Regexp::Node; $context->{parent} = PPIx::Regexp::Node->__new( $previous, $obj ); } $context->{object} = $obj; } ) { while ( my ( $name, $val ) = each %args ) { $context->{object}{$name} = $val; } $REPORT and return; @_ = ( $title ); goto &pass; } else { $title .= ": $@"; chomp $title; $REPORT and die $title; @_ = ( $title ); goto &fail; } } } 1; __END__ # ex: set textwidth=72 : PPIx-Regexp-0.055/t/xplain.t000444000765000024 5263713237102475 14777 0ustar00tomstaff000000000000package main; use 5.006; use strict; use warnings; use lib qw{ inc }; use My::Module::Test; use Test::More 0.88; # Because of done_testing(); note 'PPIx::Regexp::Node::Range'; parse( '/[a-z]/' ); value( failures => [], 0 ); choose( child => 1, child => 0, child => 0 ); class( 'PPIx::Regexp::Node::Range' ); xplain( q ); note 'PPIx::Regexp::Token::Assertion'; parse( '/^\\A\\B\\B{gcb}\\B{g}\\B{sb}\\B{wb}\\G\\K\\Z\\b\\b{gcb}\\b{g}\\b{sb}\\b{wb}\B{lb}\b{lb}\\z$/' ); value( failures => [], 0 ); choose( child => 1, child => 0 ); class( 'PPIx::Regexp::Token::Assertion' ); value( explain => [], 'Assert position is at beginning of string or after newline' ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at beginning of string' ); choose( child => 1, child => 2 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is not at word/nonword boundary' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is not at grapheme cluster boundary' ); choose( child => 1, child => 4 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is not at grapheme cluster boundary' ); choose( child => 1, child => 5 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is not at sentence boundary' ); choose( child => 1, child => 6 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is not at word boundary' ); choose( child => 1, child => 7 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at pos()' ); choose( child => 1, child => 8 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'In s///, keep everything before the \\K' ); choose( child => 1, child => 9 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at end of string, or newline before end' ); choose( child => 1, child => 10 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at word/nonword boundary' ); choose( child => 1, child => 11 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at grapheme cluster boundary' ); choose( child => 1, child => 12 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at grapheme cluster boundary' ); choose( child => 1, child => 13 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at sentence boundary' ); choose( child => 1, child => 14 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at word boundary' ); choose( child => 1, child => 15 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is not at line boundary' ); choose( child => 1, child => 16 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at line boundary' ); choose( child => 1, child => 17 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at end of string' ); choose( child => 1, child => 18 ); class( 'PPIx::Regexp::Token::Assertion' ); xplain( 'Assert position is at end of string or newline' ); note 'PPIx::Regexp::Token::Backreference'; parse( '/(?x)\\1\\g-1\\g{foo}/' ); value( failures => [], 0 ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::Backreference' ); xplain( 'Back reference to capture group 1' ); choose( child => 1, child => 2 ); class( 'PPIx::Regexp::Token::Backreference' ); xplain( 'Back reference to 1st previous capture group (1 in this regexp)' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Token::Backreference' ); xplain( q ); note 'PPIx::Regexp::Token::Backtrack'; parse( '/(*ACCEPT)(*COMMIT)(*FAIL)(*MARK:foo)(*PRUNE:bar)(*SKIP:baz)(*THEN:fee)(*:fie)(*F:foe)/' ); value( failures => [], 0 ); choose( child => 1, child => 0 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Causes match to succeed at the point of the (*ACCEPT)' ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Causes match failure when backtracked into on failure' ); choose( child => 1, child => 2 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Always fails, forcing backtrack' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Name branches of alternation, target for (*SKIP)' ); choose( child => 1, child => 4 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Prevent backtracking past here on failure' ); choose( child => 1, child => 5 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Like (*PRUNE) but also discards match to this point' ); choose( child => 1, child => 6 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Force next alternation on failure' ); choose( child => 1, child => 7 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Name branches of alternation, target for (*SKIP)' ); choose( child => 1, child => 8 ); class( 'PPIx::Regexp::Token::Backtrack' ); xplain( 'Always fails, forcing backtrack' ); note 'PPIx::Regexp::Token::CharClass::POSIX'; parse( '/[[:alnum:][:alpha:][:ascii:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:word:][:xdigit:]]/' ); value( failures => [], 0 ); choose( child => 1, child => 0, child => 0 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any alphanumeric character' ); choose( child => 1, child => 0, child => 1 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Match alphabetic' ); choose( child => 1, child => 0, child => 2 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any character in the ASCII character set' ); choose( child => 1, child => 0, child => 3 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'A GNU extension, equal to a space or a horizontal tab ("\\t")' ); choose( child => 1, child => 0, child => 4 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any control character' ); choose( child => 1, child => 0, child => 5 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any decimal digit ("[0-9]")' ); choose( child => 1, child => 0, child => 6 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any printable character, excluding a space' ); choose( child => 1, child => 0, child => 7 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any lowercase character' ); choose( child => 1, child => 0, child => 8 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any printable character' ); choose( child => 1, child => 0, child => 9 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any graphical character excluding "word" characters' ); choose( child => 1, child => 0, child => 10 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any whitespace character' ); choose( child => 1, child => 0, child => 11 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any uppercase character' ); choose( child => 1, child => 0, child => 12 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'A Perl extension, equivalent to "\\w"' ); choose( child => 1, child => 0, child => 13 ); class( 'PPIx::Regexp::Token::CharClass::POSIX' ); xplain( 'Any hexadecimal digit' ); note 'PPIx::Regexp::Token::CharClass::Simple'; parse( '/.\\C\\D\\H\\N\\R\\S\\V\\W\\X\\d\\h\\s\\v\\w\\P{Upper}\\p{Upper}/' ); value( failures => [], 0 ); choose( child => 1, child => 0 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match any character' ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match a single octet (removed in 5.23.0)' ); choose( child => 1, child => 2 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match any character but a decimal digit' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match a non-horizontal-white-space character' ); choose( child => 1, child => 4 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match any character but a new-line character' ); choose( child => 1, child => 5 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match a generic new-line character' ); choose( child => 1, child => 6 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match non-white-space character' ); choose( child => 1, child => 7 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match a non-vertical-white-space character' ); choose( child => 1, child => 8 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match non-word character' ); choose( child => 1, child => 9 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match a Unicode extended grapheme cluster' ); choose( child => 1, child => 10 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match decimal digit' ); choose( child => 1, child => 11 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match a horizontal-white-space character' ); choose( child => 1, child => 12 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match white-space character' ); choose( child => 1, child => 13 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match a vertical-white-space character' ); choose( child => 1, child => 14 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match word character' ); choose( child => 1, child => 15 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match character without Unicode or custom property \'Upper\'' ); choose( child => 1, child => 16 ); class( 'PPIx::Regexp::Token::CharClass::Simple' ); xplain( 'Match character with Unicode or custom property \'Upper\'' ); note 'PPIx::Regexp::Token::Code'; parse( '/(?{foo()})/' ); value( failures => [], 0 ); choose( child => 1, child => 0, child => 0 ); class( 'PPIx::Regexp::Token::Code' ); xplain( 'Perl expression' ); note 'PPIx::Regexp::Token::Comment'; parse( '/(?#foo)/' ); value( failures => [], 0 ); choose( child => 1, start => 1 ); class( 'PPIx::Regexp::Token::Comment' ); xplain( 'Comment' ); note 'PPIx::Regexp::Token::Condition'; parse( '/(?(DEFINE))(?(R))(?(1))(?())(?(R1))(?(R&foo))/' ); value( failures => [], 0 ); choose( child => 1, child => 0, child => 0 ); class( 'PPIx::Regexp::Token::Condition' ); xplain( 'Define a group to be recursed into' ); choose( child => 1, child => 1, child => 0 ); class( 'PPIx::Regexp::Token::Condition' ); xplain( 'True if recursing' ); choose( child => 1, child => 2, child => 0 ); class( 'PPIx::Regexp::Token::Condition' ); xplain( 'True if capture group 1 matched' ); choose( child => 1, child => 3, child => 0 ); class( 'PPIx::Regexp::Token::Condition' ); xplain( 'True if capture group \'foo\' matched' ); choose( child => 1, child => 4, child => 0 ); class( 'PPIx::Regexp::Token::Condition' ); xplain( 'True if recursing directly inside capture group 1' ); choose( child => 1, child => 5, child => 0 ); class( 'PPIx::Regexp::Token::Condition' ); xplain( 'True if recursing directly inside capture group \'foo\'' ); note 'PPIx::Regexp::Token::Control'; parse( '/\\E\\F\\L\\Q\\U\\l\\u/' ); value( failures => [], 0 ); choose( child => 1, child => 0 ); class( 'PPIx::Regexp::Token::Control' ); xplain( 'End of interpolation control' ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::Control' ); xplain( 'Fold case until \\E' ); choose( child => 1, child => 2 ); class( 'PPIx::Regexp::Token::Control' ); xplain( 'Lowercase until \\E' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Token::Control' ); xplain( 'Quote metacharacters until \\E' ); choose( child => 1, child => 4 ); class( 'PPIx::Regexp::Token::Control' ); xplain( 'Uppercase until \\E' ); choose( child => 1, child => 5 ); class( 'PPIx::Regexp::Token::Control' ); xplain( 'Lowercase next character' ); choose( child => 1, child => 6 ); class( 'PPIx::Regexp::Token::Control' ); xplain( 'Uppercase next character' ); note 'PPIx::Regexp::Token::Delimiter'; parse( '//' ); value( failures => [], 0 ); choose( child => 1, start => 0 ); class( 'PPIx::Regexp::Token::Delimiter' ); xplain( 'Regular expression or replacement string delimiter' ); choose( child => 1, finish => 0 ); class( 'PPIx::Regexp::Token::Delimiter' ); xplain( 'Regular expression or replacement string delimiter' ); note 'PPIx::Regexp::Token::Greediness'; parse( '/x*?y*+/' ); value( failures => [], 0 ); choose( child => 1, child => 2 ); class( 'PPIx::Regexp::Token::Greediness' ); xplain( 'match shortest string first' ); choose( child => 1, child => 5 ); class( 'PPIx::Regexp::Token::Greediness' ); xplain( 'match longest string and give nothing back' ); note 'PPIx::Regexp::Token::GroupType::Assertion'; parse( '/(?!x)(? [], 0 ); choose( child => 1, child => 0, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Assertion' ); xplain( 'Negative look-ahead assertion' ); choose( child => 1, child => 1, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Assertion' ); xplain( 'Negative look-behind assertion' ); choose( child => 1, child => 2, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Assertion' ); xplain( 'Positive look-behind assertion' ); choose( child => 1, child => 3, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Assertion' ); xplain( 'Positive look-ahead assertion' ); note 'PPIx::Regexp::Token::GroupType::BranchReset'; parse( '/(?|(foo)|(bar))/' ); value( failures => [], 0 ); choose( child => 1, child => 0, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::BranchReset' ); xplain( 'Re-use capture group numbers' ); note 'PPIx::Regexp::Token::GroupType::Code'; parse( '/(?{foo()})(?p{bar()})(??{baz()})/' ); value( failures => [], 0 ); choose( child => 1, child => 0, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Code' ); xplain( 'Evaluate code. Always matches.' ); choose( child => 1, child => 1, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Code' ); xplain( 'Evaluate code, use as regexp at this point (removed in 5.9.5)' ); choose( child => 1, child => 2, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Code' ); xplain( 'Evaluate code, use as regexp at this point' ); note 'PPIx::Regexp::Token::GroupType::NamedCapture'; parse( '/(?\\d)/' ); value( failures => [], 0 ); choose( child => 1, child => 0, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::NamedCapture' ); xplain( 'Capture match into \'foo\'' ); note 'PPIx::Regexp::Token::GroupType::Subexpression'; parse( '/(?>x)/' ); value( failures => [], 0 ); choose( child => 1, child => 0, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Subexpression' ); xplain( 'Match subexpression without backtracking' ); note 'PPIx::Regexp::Token::GroupType::Switch'; parse( '/(?(1)x|y)/' ); value( failures => [], 0 ); choose( child => 1, child => 0, type => 0 ); class( 'PPIx::Regexp::Token::GroupType::Switch' ); xplain( 'Match one of the following \'|\'-delimited alternatives' ); note 'PPIx::Regexp::Token::Literal'; parse( '/x/' ); value( failures => [], 0 ); choose( child => 1, child => 0 ); class( 'PPIx::Regexp::Token::Literal' ); xplain( 'Literal character' ); note 'PPIx::Regexp::Token::Modifier'; parse( '/(foo(?u-n:(bar)))/smxna' ); value( failures => [], 0 ); choose( child => 1, child => 0, child => 3, type => 0 ); class( 'PPIx::Regexp::Token::Modifier' ); xplain( 'u: match using Unicode semantics; -n: parentheses capture' ); choose( child => 2 ); class( 'PPIx::Regexp::Token::Modifier' ); xplain( 'a: restrict non-Unicode classes to ASCII; m: ^ and $ match within string; n: parentheses do not capture; s: . can match newline; x: ignore whitespace and comments' ); note 'PPIx::Regexp::Token::NoOp'; parse ( '/\\N{}/' ); value ( failures => [], 0 ); choose ( child => 1, start => 1 ); class ( 'PPIx::Regexp::Token::NoOp' ); xplain ( 'Not significant' ); note 'PPIx::Regexp::Token::Operator'; parse( '/(?[(\\w-[[:lower:]])|\\p{Greek}])|[^a-z]/' ); value( failures => [], 0 ); choose( child => 1, child => 0, child => 0, child => 1 ); class( 'PPIx::Regexp::Token::Operator' ); xplain( 'Subtraction operator' ); choose( child => 1, child => 0, child => 1 ); class( 'PPIx::Regexp::Token::Operator' ); xplain( 'Union operator' ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::Operator' ); xplain( 'Alternation operator' ); choose( child => 1, child => 2, type => 0 ); class( 'PPIx::Regexp::Token::Operator' ); xplain( 'Inversion operator' ); choose( child => 1, child => 2, child => 0, child => 1 ); class( 'PPIx::Regexp::Token::Operator' ); xplain( 'Range operator' ); note 'PPIx::Regexp::Token::Quantifier'; parse( '/a*b+c?/' ); value( failures => [], 0 ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::Quantifier' ); xplain( 'match zero or more times' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Token::Quantifier' ); xplain( 'match one or more times' ); choose( child => 1, child => 5 ); class( 'PPIx::Regexp::Token::Quantifier' ); xplain( 'match zero or one time' ); note 'PPIx::Regexp::Token::Structure'; parse( '/(?[(\\w-[0-9])]){1,3}/' ); value( failures => [], 0 ); choose( child => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'Match regexp' ); choose( child => 1, start => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'Regular expression or replacement string delimiter' ); choose( child => 1, child => 0, start => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'Extended character class' ); choose( child => 1, child => 0, child => 0, start => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'Capture or grouping' ); choose( child => 1, child => 0, child => 0, child => 2, start => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'Character class' ); choose( child => 1, child => 0, child => 0, child => 2, finish => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'End character class' ); choose( child => 1, child => 0, child => 0, finish => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'End capture or grouping' ); choose( child => 1, child => 0, finish => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'End extended character class' ); choose( child => 1, finish => 0 ); class( 'PPIx::Regexp::Token::Structure' ); xplain( 'Regular expression or replacement string delimiter' ); note 'PPIx::Regexp::Token::Recursion'; parse( '/(?x(?1))(?R)(?0)(?&z)/' ); value( failures => [], 0 ); choose( child => 1, child => 0, child => 1 ); class( 'PPIx::Regexp::Token::Recursion' ); xplain( 'Recurse into capture group 1' ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Token::Recursion' ); xplain( 'Recurse to beginning of regular expression' ); choose( child => 1, child => 2 ); class( 'PPIx::Regexp::Token::Recursion' ); xplain( 'Recurse to beginning of regular expression' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Token::Recursion' ); xplain( 'Recurse into capture group \'z\'' ); note 'PPIx::Regexp::Token::Unmatched'; parse( '/)/' ); value( failures => [], 1 ); choose( child => 1, child => 0 ); class( 'PPIx::Regexp::Token::Unmatched' ); xplain( 'Unmatched token' ); note 'PPIx::Regexp::Token::Whitespace'; parse( 's{ (?[ \\d])} {x}x' ); value( failures => [], 0 ); choose( child => 1, start => 1 ); class( 'PPIx::Regexp::Token::Whitespace' ); xplain( 'Not significant under /x' ); choose( child => 1, child => 0, start => 1 ); class( 'PPIx::Regexp::Token::Whitespace' ); xplain( 'Not significant in extended character class' ); choose( child => 2 ); class( 'PPIx::Regexp::Token::Whitespace' ); xplain( 'Not significant' ); note 'PPIx::Regexp::Structure::Capture'; parse( '/(\\d+)(?\\w+)/' ); value( failures => [], 0 ); choose( child => 1, child => 0 ); class( 'PPIx::Regexp::Structure::Capture' ); xplain( 'Capture group number 1' ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Structure::Capture' ); xplain( 'Named capture group \'foo\' (number 2)' ); note 'PPIx::Regexp::Structure::Quantifier'; parse( '/x{1,4}y{2,}z{3}w{$foo}/' ); value( failures => [], 0 ); choose( child => 1, child => 1 ); class( 'PPIx::Regexp::Structure::Quantifier' ); xplain( 'match 1 to 4 times' ); choose( child => 1, child => 3 ); class( 'PPIx::Regexp::Structure::Quantifier' ); xplain( 'match 2 or more times' ); choose( child => 1, child => 5 ); class( 'PPIx::Regexp::Structure::Quantifier' ); xplain( 'match exactly 3 times' ); choose( child => 1, child => 7 ); class( 'PPIx::Regexp::Structure::Quantifier' ); xplain( 'match $foo times' ); note 'PPIx::Regexp::Structure::Regexp'; parse( '/x/' ); value( failures => [], 0 ); choose( child => 1 ); class( 'PPIx::Regexp::Structure::Regexp' ); xplain( 'Regular expression' ); note 'PPIx::Regexp::Structure::Replacement'; parse( 's/x/y/' ); value( failures => [], 0 ); choose( child => 2 ); class( 'PPIx::Regexp::Structure::Replacement' ); xplain( 'Replacement string or expression' ); note 'PPIx::Regexp'; parse( '/x/' ); value( failures => [], 0 ); choose(); class( 'PPIx::Regexp' ); xplain( undef ); done_testing; sub xplain { splice @_, 0, 0, explain => []; goto &value; } 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/xt000755000765000024 013237102475 13315 5ustar00tomstaff000000000000PPIx-Regexp-0.055/xt/author000755000765000024 013237102475 14617 5ustar00tomstaff000000000000PPIx-Regexp-0.055/xt/author/changes.t000444000765000024 60213237102475 16527 0ustar00tomstaff000000000000package main; use 5.010; use strict; use warnings; use Test::More 0.88; # Because of done_testing(); BEGIN { eval { require Test::CPAN::Changes; Test::CPAN::Changes->import(); 1; } or do { plan skip_all => 'Unable to load Test::CPAN::Changes'; exit; }; } changes_file_ok( Changes => { next_token => 'next_release' } ); done_testing; 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/xt/author/critic.t000444000765000024 53613237102475 16402 0ustar00tomstaff000000000000package main; use strict; use warnings; use File::Spec; use Test::More 0.88; BEGIN { eval { require Test::Perl::Critic; Test::Perl::Critic->import( -profile => File::Spec->catfile(qw{xt author perlcriticrc}) ); 1; } or do { plan skip_all => 'Test::Perl::Critic required to criticize code.'; exit; }; } all_critic_ok(); 1; PPIx-Regexp-0.055/xt/author/executable.t000444000765000024 111413237102475 17257 0ustar00tomstaff000000000000package main; use strict; use warnings; use ExtUtils::Manifest qw{maniread}; use Test::More 0.88; my $manifest = maniread(); foreach ( sort keys %{ $manifest } ) { m{ \A bin / }smx and next; m{ \A eg / }smx and next; m{ \A tools / }smx and next; ok ! is_executable(), "$_ should not be executable"; } done_testing; sub is_executable { my @stat = stat $_; $stat[2] & oct(111) and return 1; open my $fh, '<', $_ or die "Unable to open $_: $!\n"; local $_ = <$fh>; close $fh; return m{ \A [#]! .* perl }smx; } 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/xt/author/kwalitee.t000444000765000024 53213237102475 16726 0ustar00tomstaff000000000000package main; use 5.006002; use strict; use warnings; use Test::More 0.88; eval { require Test::Kwalitee; Test::Kwalitee->import(); -f 'Debian_CPANTS.txt' # Don't know what this is, and unlink 'Debian_CPANTS.txt'; # but _I_ didn't order it. 1; } or plan skip_all => 'Test::Kwalitee not found'; 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/xt/author/manifest.t000444000765000024 116213237102475 16747 0ustar00tomstaff000000000000package main; use strict; use warnings; BEGIN { eval { require Test::More; Test::More->VERSION( 0.88 ); # Because of done_testing() Test::More->import(); 1; } or do { print <import( qw{ manicheck filecheck } ); 1; } or do { plan( skip_all => "ExtUtils::Manifest required" ); exit; }; } plan( tests => 2 ); is( join( ' ', manicheck() ), '', 'Missing files per manifest' ); is( join( ' ', filecheck() ), '', 'Files not in MANIFEST or MANIFEST.SKIP' ); 1; PPIx-Regexp-0.055/xt/author/minimum_perl.t000444000765000024 262613237102475 17644 0ustar00tomstaff000000000000package main; use 5.008; use strict; use warnings; use Test::More 0.88; # Because of done_testing(); eval { require ExtUtils::Manifest; 1; } or plan skip_all => 'Unable to load ExtUtils::Manifest'; eval { require Perl::MinimumVersion; 1; } or plan skip_all => 'Unable to load Perl::MinimumVersion'; eval { require version; 1; } or plan skip_all => 'Unable to load version'; use lib qw{ inc }; use My::Module::Meta; my $min_perl = My::Module::Meta->requires_perl(); my $min_perl_vers = version->parse( $min_perl ); my $manifest = ExtUtils::Manifest::maniread(); foreach my $fn ( sort keys %{ $manifest } ) { $fn =~ m{ \A xt/ }smx and next; is_perl( $fn ) or next; my $doc = Perl::MinimumVersion->new( $fn ); cmp_ok $doc->minimum_version(), 'le', $min_perl, "$fn works under Perl $min_perl"; my $ppi_doc = $doc->Document(); foreach my $inc ( @{ $ppi_doc->find( 'PPI::Statement::Include' ) || [] } ) { my $vers = $inc->version() or next; cmp_ok( version->parse( $vers ), '==', $min_perl_vers, "$fn has use $min_perl, rather than some other version" ); last; } } done_testing; sub is_perl { my ( $fn ) = @_; $fn =~ m/ [.] (?: pm | t | pod | (?i: pl ) ) \z /smx and return 1; -f $fn and -T _ or return 0; open my $fh, '<', $fn or return 0; local $_ = <$fh>; close $fh; return m/ perl /smx; } 1; # ex: set textwidth=72 : PPIx-Regexp-0.055/xt/author/perlcriticrc000444000765000024 370413237102475 17370 0ustar00tomstaff000000000000severity = stern theme = core [Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval] allow_includes = 1 [Perl::Critic::Policy::Documentation::PodSpelling] spell_command = aspell list [Perl::Critic::Policy::ErrorHandling::RequireCheckingReturnValueOfEval] # The default is 3 ('harsh'), but I think this is more severe than that. severity = stern [Perl::Critic::Policy::InputOutput::ProhibitInteractiveTest] # Perl::Critic and Perl Best Practices prefer the IO::Interactive # is_interactive() subroutine to -T STDIN. But that assumes that # ARGV is used for input, and that you don't want to be interactive # if output goes to a pipe. I do not want these assumptions, but # rather than disable them in the code I am simply assigning them # a severity slightly higher than I currently use. severity = harsh [Perl::Critic::Policy::InputOutput::RequireCheckedOpen] # For some reason the default is 3 ('harsh'). But IM(NS)HO this # kind of thing should be a 5. So: severity = gentle [Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines] severity = stern private_name_regex = _(?!_)\w+ [Perl::Critic::Policy::Subroutines::RequireArgUnpacking] short_subroutine_statements = 3 [Perl::Critic::Policy::Subroutines::RequireFinalReturn] terminal_funcs = CORE::exit [Perl::Critic::Policy::TestingAndDebugging::ProhibitNoStrict] allow = refs [Perl::Critic::Policy::TestingAndDebugging::ProhibitNoWarnings] allow = exiting once substr uninitialized [Perl::Critic::Policy::ValuesAndExpressions::ProhibitConstantPragma] # Perl::Critic and Perl Best Practices do not like the 'constant' # pragma because it does not interpolate. It really does, the # syntax is just different. Rather than disable the things in the # source, I'm just assigning them a severity slightly greater than # I customarily use. severity = harsh [Perl::Critic::Policy::Variables::ProhibitUnusedVarsStricter] add_themes = core allow_unused_subroutine_arguments = 0 severity = stern PPIx-Regexp-0.055/xt/author/pod.t000444000765000024 45313237102475 15705 0ustar00tomstaff000000000000package main; use strict; use warnings; use Test::More 0.88; BEGIN { eval { require Test::Pod; Test::Pod->VERSION (1.00); Test::Pod->import(); 1; } or do { print <VERSION(1.00); Test::Pod::Coverage->import(); 1; } or do { print < [ qr{^[[:upper:]\d_]+$}, ], coverage_class => 'Pod::Coverage::CountParents' }); 1; PPIx-Regexp-0.055/xt/author/pod_spelling.t000444000765000024 125313237102475 17621 0ustar00tomstaff000000000000package main; use strict; use warnings; BEGIN { eval { require Test::Spelling; Test::Spelling->import(); 1; } or do { print "1..0 # skip Test::Spelling not available.\n"; exit; }; } add_stopwords (); all_pod_files_spelling_ok (); 1; __DATA__ Autoconf charnames errstr hocery indices infeasible instantiation jb kluginess lexed lexes merchantability nav navigational perlrecharclass perluniprops POSIX postderef postfix PPI ppi PPI's reblesses repl schild schildren scontent subclasses subscripted TODO tokenization Tokenize tokenize tokenized tokenizer's TOKENIZERS tokenizers tokenizes tokenizing trigraphs Un unicode unterminated UTF version's Wyant XS PPIx-Regexp-0.055/xt/author/unicode_short_charclass.t000444000765000024 252113237102475 22031 0ustar00tomstaff000000000000package main; use 5.006; use strict; use warnings; use PPIx::Regexp; use Test::More 0.88; # Because of done_testing(); note <<'EOD'; Scraping perluniprops seems fragile because it is, but I can not think of better way to find out what all the single-character property names are. If this breaks too often I may end up going to just matching [[:upper:]] or something like that. Note to self: the relevant regular expression is in PPIx::Regexp::Token::CharClass::Simple method __PPIX_TOKENIZER__regexp() EOD my %prop; foreach ( `perldoc -oText perluniprops` ) { m/ \\p [{] ( . ) [}] .*? \\p [{] ( .{2,}? ) [}] /smx or next; $prop{$1} ||= $2; } is_deeply \%prop, { C => 'Other', L => 'Letter', M => 'Mark', N => 'Number', P => 'Punct', S => 'Symbol', Z => 'Separator', }, 'All single-character properties are accounted for'; foreach my $letter ( sort keys %prop ) { my $token = "\\p$letter"; my $text = "/$token/"; my $pre = PPIx::Regexp->new( $text ); my $re = $pre->regular_expression(); my @kids = $re->children(); cmp_ok scalar( @kids ), '==', 1, "'$text' parsed to a single token"; cmp_ok $kids[0]->content(), 'eq', $token, "'$text' contains token $token"; isa_ok $kids[0], 'PPIx::Regexp::Token::CharClass::Simple', "Token $token"; } done_testing; 1; # ex: set textwidth=72 :