PPIx-Regexp-0.036000755000765000765 012262112576 13730 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/Build.PL000444000765000765 201012262112576 15352 0ustar00tommessagebus000000000000use 5.006; use strict; use warnings; use lib qw{ inc }; use Module::Build; use PPIx::Regexp::Build; use PPIx::Regexp::Meta; (my $mbv = Module::Build->VERSION()) =~ s/_//g; my $meta = PPIx::Regexp::Meta->new(); my %args = ( dist_author => 'Tom Wyant (wyant at cpan dot org)', dist_abstract => 'Parse regular expressions', module_name => 'PPIx::Regexp', build_requires => $meta->build_requires(), requires => $meta->requires( perl => $meta->requires_perl(), ), dynamic_config => 1, license => 'perl', ); $mbv >= 0.28 and $args{meta_merge} = { no_index => { directory => [qw{ inc t xt }], }, resources => { bugtracker => 'https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp', }, }; # 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 = PPIx::Regexp::Build->new (%args); $bldr->create_build_script (); # ex: set textwidth=72 : PPIx-Regexp-0.036/Changes000444000765000765 3541112262112576 15404 0ustar00tommessagebus0000000000000.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 tp 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 No changes since 0.033_01 0.033_01 2013-05-05 T. R. Wyant Correct spelling and grammar errors in POD and comments. RT #85050. Thanks David Steinbrunner for catching these. 0.033 2013-02-22 T. R. Wyant 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. 0.032 2013-02-06 T. R. Wyant 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 No changes from 0.028_02. 0.028_02 2012-12-31 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. 0.028_01 2012-12-20 T. R. Wyant 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. The default-modifier functionality is no longer considered experimental. No code changes since 0.021_11. 0.021_11 2011-11-15 T. R. Wyant 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. THE DEFAULT-MODIFIER FUNCTIONALITY IS EXPERIMENTAL, AND MAY BE CHANGED WITHOUT NOTICE until the next production release. 0.021_10 2011-11-14 T. R. Wyant 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. THIS FUNCTIONALITY IS EXPERIMENTAL, AND MAY BE CHANGED OR REVOKED WITHOUT WARNING. 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 No changes (other than version) since 0.017_02. 0.017_02 2011-01-31 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. 0.017_01 2011-01-28 T. R. Wyant Take account of possible '$' or '@' casts before a symbol in an interpolation (e.g. $$foo{bar}, which is equivalent to $foo->{bar}). 0.017 2011-01-26 T. R. Wyant 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. Update copyright to 2011. 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 No changes from 0.010_01. 0.010_01 2010-09-11 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. 0.007_01 2010-06-28 T. R. Wyant 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. 0.006_01 2010-04-23 T. R. Wyant 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 Update copyright from 2009 to 2009-2010. 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. PPIx-Regexp-0.036/Makefile.PL000444000765000765 222612262112576 16041 0ustar00tommessagebus000000000000use strict; use warnings; use lib qw{ inc }; use ExtUtils::MakeMaker; use PPIx::Regexp::Meta; (my $mmv = ExtUtils::MakeMaker->VERSION) =~ s/_//g; my $meta = PPIx::Regexp::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 => 'Tom Wyant (wyant at cpan dot org)', ABSTRACT => 'Parse regular expressions', ); $mmv >= 6.31 and $args{LICENSE} = 'perl'; $mmv >= 6.4501 and $args{META_ADD} = { no_index => { directory => [ qw{ inc t xt } ], }, }; $mmv >= 6.4501 and $args{META_MERGE} = { dynamic_config => 1, resources => { bugtracker => 'https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp', license => 'http://dev.perl.org/licenses/', }, }; $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); # ex: set textwidth=72 : PPIx-Regexp-0.036/MANIFEST000444000765000765 505112262112576 15217 0ustar00tommessagebus000000000000Build.PL Changes eg/interpolated eg/predump eg/prenav eg/preslurp eg/README inc/PPIx/Regexp/Build.pm inc/PPIx/Regexp/Meta.pm inc/PPIx/Regexp/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/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/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/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/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 MANIFEST.SKIP META.yml README t/basic.t t/parse.t t/unit.t t/version.t xt/author/changes.t xt/author/critic.t xt/author/executable.t xt/author/kwalitee.t xt/author/manifest.t xt/author/perlcriticrc xt/author/pod.t xt/author/pod_coverage.t xt/author/pod_spelling.t META.json PPIx-Regexp-0.036/MANIFEST.SKIP000444000765000765 36112262112576 15743 0ustar00tommessagebus000000000000^\.# /\.# ^_build/ ^blib/ ^Build$ ^Changes_Development$ ^cover_db/ CVS/ ^foo ^.git/ ^.gitignore$ ^html/ ^Makefile$ ^MANIFEST\. ^meta/ ^MYMETA\.(?:json|yml)$ ^pm_to_blib$ \.old$ ^pod2htm.\.tmp$ ^ref/ \.svn/ \.swp$ ^tools/ ^TODO$ ^PPIx-Regexp PPIx-Regexp-0.036/META.json000444000765000765 2211312262112576 15525 0ustar00tommessagebus000000000000{ "abstract" : "Parse regular expressions", "author" : [ "Tom Wyant (wyant at cpan dot org)" ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4203", "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" : { "List::MoreUtils" : "0", "List::Util" : "0", "PPI::Document" : "1.117", "Scalar::Util" : "0", "Task::Weaken" : "0", "perl" : "5.006" } } }, "provides" : { "PPIx::Regexp" : { "file" : "lib/PPIx/Regexp.pm", "version" : "0.036" }, "PPIx::Regexp::Constant" : { "file" : "lib/PPIx/Regexp/Constant.pm", "version" : "0.036" }, "PPIx::Regexp::Dumper" : { "file" : "lib/PPIx/Regexp/Dumper.pm", "version" : "0.036" }, "PPIx::Regexp::Element" : { "file" : "lib/PPIx/Regexp/Element.pm", "version" : "0.036" }, "PPIx::Regexp::Lexer" : { "file" : "lib/PPIx/Regexp/Lexer.pm", "version" : "0.036" }, "PPIx::Regexp::Node" : { "file" : "lib/PPIx/Regexp/Node.pm", "version" : "0.036" }, "PPIx::Regexp::Node::Range" : { "file" : "lib/PPIx/Regexp/Node/Range.pm", "version" : "0.036" }, "PPIx::Regexp::Structure" : { "file" : "lib/PPIx/Regexp/Structure.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Assertion" : { "file" : "lib/PPIx/Regexp/Structure/Assertion.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::BranchReset" : { "file" : "lib/PPIx/Regexp/Structure/BranchReset.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Capture" : { "file" : "lib/PPIx/Regexp/Structure/Capture.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::CharClass" : { "file" : "lib/PPIx/Regexp/Structure/CharClass.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Code" : { "file" : "lib/PPIx/Regexp/Structure/Code.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Main" : { "file" : "lib/PPIx/Regexp/Structure/Main.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Modifier" : { "file" : "lib/PPIx/Regexp/Structure/Modifier.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::NamedCapture" : { "file" : "lib/PPIx/Regexp/Structure/NamedCapture.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Quantifier" : { "file" : "lib/PPIx/Regexp/Structure/Quantifier.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::RegexSet" : { "file" : "lib/PPIx/Regexp/Structure/RegexSet.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Regexp" : { "file" : "lib/PPIx/Regexp/Structure/Regexp.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Replacement" : { "file" : "lib/PPIx/Regexp/Structure/Replacement.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Subexpression" : { "file" : "lib/PPIx/Regexp/Structure/Subexpression.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Switch" : { "file" : "lib/PPIx/Regexp/Structure/Switch.pm", "version" : "0.036" }, "PPIx::Regexp::Structure::Unknown" : { "file" : "lib/PPIx/Regexp/Structure/Unknown.pm", "version" : "0.036" }, "PPIx::Regexp::Support" : { "file" : "lib/PPIx/Regexp/Support.pm", "version" : "0.036" }, "PPIx::Regexp::Token" : { "file" : "lib/PPIx/Regexp/Token.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Assertion" : { "file" : "lib/PPIx/Regexp/Token/Assertion.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Backreference" : { "file" : "lib/PPIx/Regexp/Token/Backreference.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Backtrack" : { "file" : "lib/PPIx/Regexp/Token/Backtrack.pm", "version" : "0.036" }, "PPIx::Regexp::Token::CharClass" : { "file" : "lib/PPIx/Regexp/Token/CharClass.pm", "version" : "0.036" }, "PPIx::Regexp::Token::CharClass::POSIX" : { "file" : "lib/PPIx/Regexp/Token/CharClass/POSIX.pm", "version" : "0.036" }, "PPIx::Regexp::Token::CharClass::POSIX::Unknown" : { "file" : "lib/PPIx/Regexp/Token/CharClass/POSIX/Unknown.pm", "version" : "0.036" }, "PPIx::Regexp::Token::CharClass::Simple" : { "file" : "lib/PPIx/Regexp/Token/CharClass/Simple.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Code" : { "file" : "lib/PPIx/Regexp/Token/Code.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Comment" : { "file" : "lib/PPIx/Regexp/Token/Comment.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Condition" : { "file" : "lib/PPIx/Regexp/Token/Condition.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Control" : { "file" : "lib/PPIx/Regexp/Token/Control.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Delimiter" : { "file" : "lib/PPIx/Regexp/Token/Delimiter.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Greediness" : { "file" : "lib/PPIx/Regexp/Token/Greediness.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType" : { "file" : "lib/PPIx/Regexp/Token/GroupType.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType::Assertion" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Assertion.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType::BranchReset" : { "file" : "lib/PPIx/Regexp/Token/GroupType/BranchReset.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType::Code" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Code.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType::Modifier" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Modifier.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType::NamedCapture" : { "file" : "lib/PPIx/Regexp/Token/GroupType/NamedCapture.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType::Subexpression" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Subexpression.pm", "version" : "0.036" }, "PPIx::Regexp::Token::GroupType::Switch" : { "file" : "lib/PPIx/Regexp/Token/GroupType/Switch.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Interpolation" : { "file" : "lib/PPIx/Regexp/Token/Interpolation.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Literal" : { "file" : "lib/PPIx/Regexp/Token/Literal.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Modifier" : { "file" : "lib/PPIx/Regexp/Token/Modifier.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Operator" : { "file" : "lib/PPIx/Regexp/Token/Operator.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Quantifier" : { "file" : "lib/PPIx/Regexp/Token/Quantifier.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Recursion" : { "file" : "lib/PPIx/Regexp/Token/Recursion.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Reference" : { "file" : "lib/PPIx/Regexp/Token/Reference.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Structure" : { "file" : "lib/PPIx/Regexp/Token/Structure.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Unknown" : { "file" : "lib/PPIx/Regexp/Token/Unknown.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Unmatched" : { "file" : "lib/PPIx/Regexp/Token/Unmatched.pm", "version" : "0.036" }, "PPIx::Regexp::Token::Whitespace" : { "file" : "lib/PPIx/Regexp/Token/Whitespace.pm", "version" : "0.036" }, "PPIx::Regexp::Tokenizer" : { "file" : "lib/PPIx/Regexp/Tokenizer.pm", "version" : "0.036" }, "PPIx::Regexp::Util" : { "file" : "lib/PPIx/Regexp/Util.pm", "version" : "0.036" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp" }, "license" : [ "http://dev.perl.org/licenses/" ] }, "version" : "0.036" } PPIx-Regexp-0.036/META.yml000444000765000765 1457512262112576 15372 0ustar00tommessagebus000000000000--- abstract: 'Parse regular expressions' author: - 'Tom Wyant (wyant at cpan dot org)' build_requires: Test::More: 0.88 dynamic_config: 1 generated_by: 'Module::Build version 0.4203, CPAN::Meta::Converter version 2.133380' 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.036 PPIx::Regexp::Constant: file: lib/PPIx/Regexp/Constant.pm version: 0.036 PPIx::Regexp::Dumper: file: lib/PPIx/Regexp/Dumper.pm version: 0.036 PPIx::Regexp::Element: file: lib/PPIx/Regexp/Element.pm version: 0.036 PPIx::Regexp::Lexer: file: lib/PPIx/Regexp/Lexer.pm version: 0.036 PPIx::Regexp::Node: file: lib/PPIx/Regexp/Node.pm version: 0.036 PPIx::Regexp::Node::Range: file: lib/PPIx/Regexp/Node/Range.pm version: 0.036 PPIx::Regexp::Structure: file: lib/PPIx/Regexp/Structure.pm version: 0.036 PPIx::Regexp::Structure::Assertion: file: lib/PPIx/Regexp/Structure/Assertion.pm version: 0.036 PPIx::Regexp::Structure::BranchReset: file: lib/PPIx/Regexp/Structure/BranchReset.pm version: 0.036 PPIx::Regexp::Structure::Capture: file: lib/PPIx/Regexp/Structure/Capture.pm version: 0.036 PPIx::Regexp::Structure::CharClass: file: lib/PPIx/Regexp/Structure/CharClass.pm version: 0.036 PPIx::Regexp::Structure::Code: file: lib/PPIx/Regexp/Structure/Code.pm version: 0.036 PPIx::Regexp::Structure::Main: file: lib/PPIx/Regexp/Structure/Main.pm version: 0.036 PPIx::Regexp::Structure::Modifier: file: lib/PPIx/Regexp/Structure/Modifier.pm version: 0.036 PPIx::Regexp::Structure::NamedCapture: file: lib/PPIx/Regexp/Structure/NamedCapture.pm version: 0.036 PPIx::Regexp::Structure::Quantifier: file: lib/PPIx/Regexp/Structure/Quantifier.pm version: 0.036 PPIx::Regexp::Structure::RegexSet: file: lib/PPIx/Regexp/Structure/RegexSet.pm version: 0.036 PPIx::Regexp::Structure::Regexp: file: lib/PPIx/Regexp/Structure/Regexp.pm version: 0.036 PPIx::Regexp::Structure::Replacement: file: lib/PPIx/Regexp/Structure/Replacement.pm version: 0.036 PPIx::Regexp::Structure::Subexpression: file: lib/PPIx/Regexp/Structure/Subexpression.pm version: 0.036 PPIx::Regexp::Structure::Switch: file: lib/PPIx/Regexp/Structure/Switch.pm version: 0.036 PPIx::Regexp::Structure::Unknown: file: lib/PPIx/Regexp/Structure/Unknown.pm version: 0.036 PPIx::Regexp::Support: file: lib/PPIx/Regexp/Support.pm version: 0.036 PPIx::Regexp::Token: file: lib/PPIx/Regexp/Token.pm version: 0.036 PPIx::Regexp::Token::Assertion: file: lib/PPIx/Regexp/Token/Assertion.pm version: 0.036 PPIx::Regexp::Token::Backreference: file: lib/PPIx/Regexp/Token/Backreference.pm version: 0.036 PPIx::Regexp::Token::Backtrack: file: lib/PPIx/Regexp/Token/Backtrack.pm version: 0.036 PPIx::Regexp::Token::CharClass: file: lib/PPIx/Regexp/Token/CharClass.pm version: 0.036 PPIx::Regexp::Token::CharClass::POSIX: file: lib/PPIx/Regexp/Token/CharClass/POSIX.pm version: 0.036 PPIx::Regexp::Token::CharClass::POSIX::Unknown: file: lib/PPIx/Regexp/Token/CharClass/POSIX/Unknown.pm version: 0.036 PPIx::Regexp::Token::CharClass::Simple: file: lib/PPIx/Regexp/Token/CharClass/Simple.pm version: 0.036 PPIx::Regexp::Token::Code: file: lib/PPIx/Regexp/Token/Code.pm version: 0.036 PPIx::Regexp::Token::Comment: file: lib/PPIx/Regexp/Token/Comment.pm version: 0.036 PPIx::Regexp::Token::Condition: file: lib/PPIx/Regexp/Token/Condition.pm version: 0.036 PPIx::Regexp::Token::Control: file: lib/PPIx/Regexp/Token/Control.pm version: 0.036 PPIx::Regexp::Token::Delimiter: file: lib/PPIx/Regexp/Token/Delimiter.pm version: 0.036 PPIx::Regexp::Token::Greediness: file: lib/PPIx/Regexp/Token/Greediness.pm version: 0.036 PPIx::Regexp::Token::GroupType: file: lib/PPIx/Regexp/Token/GroupType.pm version: 0.036 PPIx::Regexp::Token::GroupType::Assertion: file: lib/PPIx/Regexp/Token/GroupType/Assertion.pm version: 0.036 PPIx::Regexp::Token::GroupType::BranchReset: file: lib/PPIx/Regexp/Token/GroupType/BranchReset.pm version: 0.036 PPIx::Regexp::Token::GroupType::Code: file: lib/PPIx/Regexp/Token/GroupType/Code.pm version: 0.036 PPIx::Regexp::Token::GroupType::Modifier: file: lib/PPIx/Regexp/Token/GroupType/Modifier.pm version: 0.036 PPIx::Regexp::Token::GroupType::NamedCapture: file: lib/PPIx/Regexp/Token/GroupType/NamedCapture.pm version: 0.036 PPIx::Regexp::Token::GroupType::Subexpression: file: lib/PPIx/Regexp/Token/GroupType/Subexpression.pm version: 0.036 PPIx::Regexp::Token::GroupType::Switch: file: lib/PPIx/Regexp/Token/GroupType/Switch.pm version: 0.036 PPIx::Regexp::Token::Interpolation: file: lib/PPIx/Regexp/Token/Interpolation.pm version: 0.036 PPIx::Regexp::Token::Literal: file: lib/PPIx/Regexp/Token/Literal.pm version: 0.036 PPIx::Regexp::Token::Modifier: file: lib/PPIx/Regexp/Token/Modifier.pm version: 0.036 PPIx::Regexp::Token::Operator: file: lib/PPIx/Regexp/Token/Operator.pm version: 0.036 PPIx::Regexp::Token::Quantifier: file: lib/PPIx/Regexp/Token/Quantifier.pm version: 0.036 PPIx::Regexp::Token::Recursion: file: lib/PPIx/Regexp/Token/Recursion.pm version: 0.036 PPIx::Regexp::Token::Reference: file: lib/PPIx/Regexp/Token/Reference.pm version: 0.036 PPIx::Regexp::Token::Structure: file: lib/PPIx/Regexp/Token/Structure.pm version: 0.036 PPIx::Regexp::Token::Unknown: file: lib/PPIx/Regexp/Token/Unknown.pm version: 0.036 PPIx::Regexp::Token::Unmatched: file: lib/PPIx/Regexp/Token/Unmatched.pm version: 0.036 PPIx::Regexp::Token::Whitespace: file: lib/PPIx/Regexp/Token/Whitespace.pm version: 0.036 PPIx::Regexp::Tokenizer: file: lib/PPIx/Regexp/Tokenizer.pm version: 0.036 PPIx::Regexp::Util: file: lib/PPIx/Regexp/Util.pm version: 0.036 requires: List::MoreUtils: 0 List::Util: 0 PPI::Document: 1.117 Scalar::Util: 0 Task::Weaken: 0 perl: 5.006 resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp license: http://dev.perl.org/licenses/ version: 0.036 PPIx-Regexp-0.036/README000444000765000765 321412262112576 14745 0ustar00tommessagebus000000000000PPIx-Regexp is Copyright (C) 2009-2014 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.036/eg000755000765000765 012262112576 14323 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/eg/interpolated000555000765000765 544512262112576 17110 0ustar00tommessagebus000000000000#!/usr/local/bin/perl use 5.006002; 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-2014 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.036/eg/predump000555000765000765 1624512262112576 16112 0ustar00tommessagebus000000000000#!/usr/local/bin/perl use 5.008; use strict; use warnings; use Getopt::Long 2.33; use Pod::Usage; use PPI::Document; use PPIx::Regexp::Dumper; use Scalar::Util qw{ refaddr }; our $VERSION = '0.036'; my %opt = ( default_modifiers => [], verbose => 0, ); GetOptions( \%opt, help => sub { pod2usage ( { -exitval => 0, -verbose => 2, -output => \*STDOUT, } ) }, qw{ default_modifiers|default-modifiers=s@ encoding=s files! indent=i margin=i objectify! ordinal! perl_version! significant! 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 ); $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 ); } 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}; } } sub extract_res { my ( $doc ) = @_; return ( map { @{ $doc->find( $_ ) || [] } } qw{ PPI::Token::QuoteLike::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute } ); } __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 -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 -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 -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-2014 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.036/eg/prenav000555000765000765 1333112262112576 15722 0ustar00tommessagebus000000000000#!/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-2014 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.036/eg/preslurp000555000765000765 1647412262112576 16316 0ustar00tommessagebus000000000000#!/usr/local/bin/perl use strict; use warnings; use Cwd qw{ abs_path getcwd }; use File::Find; use File::Temp; use Getopt::Long; use IO::File; use Pod::Usage; use PPI::Document; use PPIx::Regexp; use PPIx::Regexp::Dumper; use PPIx::Regexp::Tokenizer; my @legal; BEGIN { @legal = qw{ encoding=s failures! ignore=s include! ordinal! recurse! significant! tokens! verbose+ }; eval { require Archive::Any; unshift @legal, 'archive!'; }; } my %opt = ( verbose => 0, ); our $BASE = getcwd(); our @PREFIX; GetOptions( \%opt, help => sub { pod2usage ( { -exitval => 0, -verbose => 2, -output => \*STDOUT, } ) }, @legal ) or pod2usage( { -exitval => 2, -verbose => 1, -output => \*STDERR, } ); 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-2014 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.036/eg/README000444000765000765 207012262112576 15337 0ustar00tommessagebus000000000000This 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. 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. PPIx-Regexp-0.036/inc000755000765000765 012262112576 14501 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/inc/PPIx000755000765000765 012262112576 15321 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/inc/PPIx/Regexp000755000765000765 012262112576 16553 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/inc/PPIx/Regexp/Build.pm000444000765000765 375112262112576 20313 0ustar00tommessagebus000000000000package PPIx::Regexp::Build; use strict; use warnings; use base qw{ Module::Build }; our $VERSION = '0.036'; use Carp; sub ACTION_authortest { my ( $self, @args ) = @_; 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 PPIx::Regexp::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-2014 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.036/inc/PPIx/Regexp/Meta.pm000444000765000765 670712262112576 20146 0ustar00tommessagebus000000000000package PPIx::Regexp::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 requires { my ( $self, @extra ) = @_; ## if ( ! $self->distribution() ) { ## } return { 'List::MoreUtils' => 0, 'List::Util' => 0, 'PPI::Document' => 1.117, # for new( readonly => 1 ) 'Scalar::Util' => 0, 'Task::Weaken' => 0, @extra, }; } sub requires_perl { return 5.006; } 1; __END__ =head1 NAME PPIx::Regexp::Meta - Information needed to build PPIx::Regexp =head1 SYNOPSIS use lib qw{ inc }; use PPIx::Regexp::Meta; my $meta = PPIx::Regexp::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 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-2014 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.036/inc/PPIx/Regexp/Test.pm000444000765000765 4352212262112576 20213 0ustar00tommessagebus000000000000package PPIx::Regexp::Test; use strict; use warnings; use base qw{ Exporter }; 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.036'; our @EXPORT_OK = qw{ cache_count choose class cmp_ok content count different done_testing dump_result false finis equals navigate parse plan ppi result skip tokenize true value }; our @EXPORT = @EXPORT_OK; ## no critic (ProhibitAutomaticExportation) 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 is 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) my @args = @_; my $expect = pop @args; $result = undef; defined $obj and $result = $obj->content(); my $safe; if ( defined $result ) { ($safe = $result) =~ s/([\\'])/\\$1/smxg; } else { $safe = 'undef'; } @_ = ( $result, $expect, "$kind $nav content '$safe'" ); goto &is; } 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 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 = _safe( @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 }, @_ ); $initial_class = 'PPIx::Regexp::Tokenizer'; $kind = 'token'; $obj = PPIx::Regexp::Tokenizer->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 _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 _safe { 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( ' ', '[', _safe( @{ $item } ), ']' ); } elsif ( looks_like_number( $item ) ) { push @rslt, $item; } else { $item =~ s/ ( [\\'] ) /\\$1/smxg; push @rslt, "'$item'"; } } return join( ', ', @rslt ); } 1; __END__ =head1 NAME PPIx::Regexp::Test - support for testing PPIx::Regexp =head1 SYNOPSIS use lib qw{ inc }; use PPIx::Regexp::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-2014 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.036/lib000755000765000765 012262112576 14476 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx000755000765000765 012262112576 15316 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp.pm000444000765000765 4621012262112576 17266 0ustar00tommessagebus000000000000=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 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. 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. =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::Token::Modifier (); # For its modifier manipulations. use PPIx::Regexp::Util qw{ __instance }; use Scalar::Util qw{ refaddr }; our $VERSION = '0.036'; =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 do, but only the three Regexp classes mentioned previously are likely to do anything useful. 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 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 = PPIx::Regexp::Tokenizer->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. =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. =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; =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 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-2014 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.036/lib/PPIx/Regexp000755000765000765 012262112576 16550 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp/Constant.pm000444000765000765 1072012262112576 21054 0ustar00tommessagebus000000000000package PPIx::Regexp::Constant; use strict; use warnings; our $VERSION = '0.036'; use base qw{ Exporter }; our @EXPORT_OK = qw{ COOKIE_CLASS COOKIE_QUANT COOKIE_QUOTE COOKIE_REGEX_SET MINIMUM_PERL MODIFIER_GROUP_MATCH_SEMANTICS RE_CAPTURE_NAME STRUCTURE_UNKNOWN TOKEN_LITERAL TOKEN_UNKNOWN }; use constant COOKIE_CLASS => ']'; use constant COOKIE_QUANT => '}'; use constant COOKIE_QUOTE => '\\E'; use constant COOKIE_REGEX_SET => '])'; use constant MINIMUM_PERL => '5.000'; use constant MODIFIER_GROUP_MATCH_SEMANTICS => 'match_semantics'; # 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 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 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 the 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-2014 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.036/lib/PPIx/Regexp/Dumper.pm000444000765000765 4151112262112576 20521 0ustar00tommessagebus000000000000=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{ __instance }; our $VERSION = '0.036'; =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 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 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 = ( 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, }; exists $args{default_modifiers} and $self->{default_modifiers} = $args{default_modifiers}; 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} ) { $self->{object} = PPIx::Regexp::Tokenizer->new( $re, %args ) or Carp::croak( PPIx::Regexp::Tokenizer->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 ( $self, $version ) = @_; 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 ( $self, $elem ) = @_; my $rslt = $elem->perl_version_introduced() . ' <= $]'; if ( my $max = $elem->perl_version_removed() ) { $rslt .= ' < ' . $max; } return $rslt; } 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 $default_modifiers = $self->{default_modifiers} || []; @{ $default_modifiers } or return sprintf '%-8s( %s );', $subr, $self->_safe( $elem ); return sprintf '%-8s( %s, default_modifiers => %s );', $subr, $self->_safe( $elem ), $self->_safe( $default_modifiers ); } sub _format_modifiers_dump { my ( $self, $elem ) = @_; 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::__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] .= "\tfailures=" . $self->failures(); $dumper->{perl_version} and $rslt[-1] .= "\t" . $dumper->_perl_version( $self ); 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 ( $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; } { 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 } ) { $self->can( $method ) or next; my $val = $self->$method; push @rslt, defined $val ? "$method=$val" : "$method undef"; } 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 ) ); } @rslt = ( join( "\t", @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 ) ); if ( defined( my $err = $self->error() ) ) { push @rslt, $err; } else { $dumper->{perl_version} and push @rslt, $dumper->_perl_version( $self ); 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 ); } } } return join( "\t", @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-2014 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.036/lib/PPIx/Regexp/Element.pm000444000765000765 2523512262112576 20663 0ustar00tommessagebus000000000000=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::MoreUtils qw{ firstidx }; use PPIx::Regexp::Util qw{ __instance }; use Scalar::Util qw{ refaddr weaken }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL TOKEN_UNKNOWN }; our $VERSION = '0.036'; =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 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 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 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 L, and especially 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. =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 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; } =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; } } # $self->__impose_defaults( $arg, \%default ); # # This method can be called in __PPIX_TOKEN__post_make() to supply # defaults for attributes. It returns nothing. # # The arguments are hash references, which are taken in left-to-right # order, with the, with the first extant value being used. sub __impose_defaults { my ( $self, @args ) = @_; foreach my $arg ( @args ) { ref $arg eq 'HASH' or next; foreach my $key ( keys %{ $arg } ) { exists $self->{$key} or $self->{$key} = $arg->{$key}; } } return; } # Bless into TOKEN_UNKNOWN, record error message, return 1. sub __error { my ( $self, $msg ) = @_; $self->isa( 'PPIx::Token::Node' ) and confess 'Programming error - __error() must be overridden', ' for class ', ref $self; defined $msg or $msg = 'Was ' . ref $self; $self->{error} = $msg; bless $self, TOKEN_UNKNOWN; return 1; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( $self, $number ) = @_; return $number; } 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-2014 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.036/lib/PPIx/Regexp/Lexer.pm000444000765000765 3254212262112576 20350 0ustar00tommessagebus000000000000=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::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::Switch (); use PPIx::Regexp::Structure::Unknown (); use PPIx::Regexp::Token::Unmatched (); use PPIx::Regexp::Tokenizer (); use PPIx::Regexp::Util qw{ __instance }; our $VERSION = '0.036'; =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; __instance( $tokenizer, 'PPIx::Regexp::Tokenizer' ) or $tokenizer = PPIx::Regexp::Tokenizer->new( $tokenizer, %args ) or do { $errstr = PPIx::Regexp::Tokenizer->errstr(); return; }; my $self = { deferred => [], # Deferred tokens failures => 0, 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 $token = $self->_get_token() or return $self->_finalize( @content ); $token->isa( 'PPIx::Regexp::Token::Delimiter' ) or do { push @content, $token; redo; }; $self->_unget_token( $token ); } # Accept the first delimited structure. push @content, ( my $regexp = $self->_get_delimited( 'PPIx::Regexp::Structure::Regexp' ) ); # If we are a substitution ... if ( $content[0]->content() eq 's' ) { # 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( $regexp->start( 0 ) ) || 0; # Accept the next delimited structure. push @content, $self->_get_delimited( 'PPIx::Regexp::Structure::Replacement', $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 ( $regexp ) { # Retrieve the maximum capture group. my $max_capture = $regexp->max_capture_number(); # Hashify the known capture names my $capture_name = { map { $_ => 1 } $regexp->capture_names(), }; # For all the backreferences found foreach my $elem ( @{ $regexp->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; } # 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(); } 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. bless $token, TOKEN_LITERAL; 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}++; bless $token, 'PPIx::Regexp::Token::Unmatched'; 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; } } sub _curly { 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 ) { bless $args->[$inx], TOKEN_LITERAL; } # 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. sub _recover_curly { 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 to a literal. bless $content[0], TOKEN_LITERAL; # 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 ( $self, $args ) = @_; if ( __instance( $args->[0], TOKEN_LITERAL ) && __instance( $args->[1], TOKEN_UNKNOWN ) && PPIx::Regexp::Token::Quantifier->could_be_quantifier( $args->[1]->content() ) ) { bless $args->[1], 'PPIx::Regexp::Token::Quantifier'; if ( __instance( $args->[2], TOKEN_UNKNOWN ) && PPIx::Regexp::Token::Greediness->could_be_greediness( $args->[2]->content() ) ) { bless $args->[2], 'PPIx::Regexp::Token::Greediness'; } } return; } sub _in_regex_set { my ( $self ) = @_; foreach my $stack_entry ( reverse @{ $self->{_rslt} } ) { $stack_entry->[0] eq '])' and return 1; } return 0; } sub _round { 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 } ); # The instantiator will rebless based on the first token if need be. return PPIx::Regexp::Structure::Capture->_new( @{ $args } ); } sub _square { my ( $self, $args ) = @_; return PPIx::Regexp::Structure::CharClass->_new( @{ $args } ); } sub _regex_set { my ( $self, $args ) = @_; 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-2014 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.036/lib/PPIx/Regexp/Node.pm000444000765000765 2412212262112576 20151 0ustar00tommessagebus000000000000=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 List::Util qw{ max }; use PPIx::Regexp::Constant qw{ MINIMUM_PERL }; use PPIx::Regexp::Util qw{ __instance }; use Scalar::Util qw{ refaddr }; our $VERSION = '0.036'; 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; } =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. The return is a reference to the array of parents if any were found. If none 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( MINIMUM_PERL, 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 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 ] ); } # 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 ) = @_; my $rslt = 0; foreach my $elem ( $self->elements() ) { $rslt += $elem->__PPIX_LEXER__finalize(); } 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-2014 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.036/lib/PPIx/Regexp/Structure.pm000444000765000765 2526512262112576 21275 0ustar00tommessagebus000000000000=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 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.036'; 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 ); } } 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; } } =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 ( $class, $brkt, $args ) = @_; # 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. bless $args->[0], 'PPIx::Regexp::Token::GroupType::Modifier'; # Note that we do _not_ want __PPIX_TOKEN__post_make here. # Rebless the ':' as a GroupType, just so it does not look like # something to match against. bless $args->[2], 'PPIx::Regexp::Token::GroupType'; # 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. bless $args->[0], 'PPIx::Regexp::Token::GroupType::Modifier'; # Note that we do _not_ want __PPIX_TOKEN__post_make here. # Rebless the '-' and ':' as GroupType, just so they do not # look like something to match against. bless $args->[2], 'PPIx::Regexp::Token::GroupType'; bless $args->[4], 'PPIx::Regexp::Token::GroupType'; # 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. bless $args->[0], 'PPIx::Regexp::Token::GroupType::Modifier'; # Note that we do _not_ want __PPIX_TOKEN__post_make here. # 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; } sub __error { my ( $self, $msg ) = @_; defined $msg or $msg = 'Was class ' . ref $self; $self->{error} = $msg; bless $self, STRUCTURE_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-2014 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.036/lib/PPIx/Regexp/Support.pm000444000765000765 701112262112576 20716 0ustar00tommessagebus000000000000=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.036'; =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 ( $self, $char ) = @_; 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 ( $self, @args ) = @_; 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-2014 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.036/lib/PPIx/Regexp/Token.pm000444000765000765 622412262112576 20327 0ustar00tommessagebus000000000000=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}; our $VERSION = '0.036'; sub _new { my ( $class, $content ) = @_; ref $class and $class = ref $class; my $self = { content => $content, }; bless $self, $class; return $self; } sub content { my ( $self ) = @_; return $self->{content}; } sub unescaped_content { my ( $self ) = @_; my $content = $self->content(); $content =~ s/ \\ (?= . ) //smxg; return $content; } # Called after the token is manufactured. The calling sequence is # $token->__PPIX_TOKEN__post_make( $tokenizer ); sub __PPIX_TOKEN__post_make { return }; # 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 { 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-2014 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.036/lib/PPIx/Regexp/Tokenizer.pm000444000765000765 10330712262112576 21261 0ustar00tommessagebus000000000000package PPIx::Regexp::Tokenizer; use strict; use warnings; use base qw{ PPIx::Regexp::Support }; use Carp qw{ 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::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{ __instance }; use Scalar::Util qw{ looks_like_number }; our $VERSION = '0.036'; { # 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. 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( @classes ); $self->{known}{$mode} = \@found; return (@expect, @found); } sub _known_tokenizer_check { my ( $self, @args ) = @_; my $mode = $self->{mode}; my $handler = '__PPIX_TOKENIZER__' . $mode; my @found; foreach my $class ( @args ) { $class->can( $handler ) or next; push @found, $class; } return @found; } } { 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_re => undef, # Recognize finishing delimiter. 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. prior => TOKEN_UNKNOWN, # Prior significant token. source => $re, # The object we were initialized with. trace => __PACKAGE__->_defined_or( $args{trace}, $ENV{PPIX_REGEXP_TOKENIZER_TRACE}, 0 ), }; if ( __instance( $re, 'PPI::Element' ) ) { $self->{content} = $re->content(); } elsif ( ref $re ) { $errstr = ref( $re ) . ' not supported'; return; } else { $self->{content} = $re; } bless $self, $class; $self->{content} = $self->decode( $self->{content} ); if ( $self->{content} =~ m/ \s+ \z /smx ) { $self->{cursor_limit} = $-[0]; } else { $self->{cursor_limit} = length $self->{content}; } $self->{trace} and warn "\ntokenizing '$self->{content}'\n"; return $self; } 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; my $nest = 0; while ( ++$inx < $self->{cursor_limit} ) { my $char = substr $self->{content}, $inx, 1; 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_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 $character = substr( $self->{content}, $self->{cursor_curr}, 1 ); return ( __PACKAGE__->$handler( $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 ) or return; $token->significant() and $self->{expect} = undef; $token->__PPIX_TOKEN__post_make( $self, $arg ); $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} = $token; return $token; } sub match { my ( $self ) = @_; return $self->{match}; } sub modifier { my ( $self, $modifier ) = @_; return $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->{mode} = 'finish'; $self->{cursor_limit}++; } 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 ) = @_; defined $method or return $self->{prior}; $self->{prior}->can( $method ) or confess 'Programming error - ', ( ref $self->{prior} || $self->{prior} ), ' does not support method ', $method; return $self->{prior}->$method( @args ); } sub significant { return 1; } sub tokens { my ( $self ) = @_; my @rslt; while ( my $token = $self->next_token() ) { push @rslt, $token; } return @rslt; } 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 __PPIX_TOKENIZER__init { my ( $class, $tokenizer, $character ) = @_; $tokenizer->{mode} = 'kaput'; $tokenizer->{content} =~ m/ \A \s* ( qr | m | s )? ( \s* ) ( [^\w\s] ) /smx or return $tokenizer->make_token( length( $tokenizer->{content} ), TOKEN_UNKNOWN, { error => 'Tokenizer found illegal first characters', }, ); # my ( $type, $white, $delim ) = ( $1, $2, $3 ); my ( $type, $white ) = ( $1, $2 ); my $start_pos = defined $-[1] ? $-[1] : defined $-[2] ? $-[2] : defined $-[3] ? $-[3] : 0; defined $type or $type = ''; $tokenizer->{type} = $type; my @tokens; $start_pos and push @tokens, $tokenizer->make_token( $start_pos, 'PPIx::Regexp::Token::Whitespace' ); push @tokens, $tokenizer->make_token( length $type, 'PPIx::Regexp::Token::Structure' ); length $white > 0 and push @tokens, $tokenizer->make_token( length $white, 'PPIx::Regexp::Token::Whitespace' ); { my @mods = @{ $tokenizer->{default_modifiers} }; if ( $tokenizer->{content} =~ m/ ( [[:lower:]]* ) \s* \z /smx ) { my $mod = $1; $tokenizer->{cursor_limit} -= length $mod; push @mods, $mod; } $tokenizer->{effective_modifiers} = PPIx::Regexp::Token::Modifier::__aggregate_modifiers ( @mods ); $tokenizer->{modifiers} = [ { %{ $tokenizer->{effective_modifiers} } }, ]; $tokenizer->{cursor_modifiers} = $tokenizer->{cursor_limit}; } $tokenizer->{delimiter_start} = substr $tokenizer->{content}, $tokenizer->{cursor_curr}, 1; if ( $type eq 's' and my $offset = $tokenizer->find_matching_delimiter() ) { $tokenizer->{cursor_limit} = $tokenizer->{cursor_curr} + $offset; } else { $tokenizer->{cursor_limit} = $tokenizer->{cursor_modifiers} - 1; } $tokenizer->{delimiter_finish} = substr $tokenizer->{content}, $tokenizer->{cursor_limit}, 1; $tokenizer->{delimiter_re} = undef; push @tokens, $tokenizer->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ); $tokenizer->{mode} = 'regexp'; return @tokens; } sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; my $mode = $tokenizer->{mode}; my $handler = '__PPIX_TOKENIZER__' . $mode; $tokenizer->{cursor_orig} = $tokenizer->{cursor_curr}; foreach my $class( $tokenizer->_known_tokenizers() ) { my @tokens = grep { $_ } $class->$handler( $tokenizer, $character ); $tokenizer->{trace} and warn $class, "->$handler( \$tokenizer, '$character' )", " => (@tokens)\n"; @tokens and return ( map { ref $_ ? $_ : $tokenizer->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->( $class, $tokenizer, $character ); } *__PPIX_TOKENIZER__repl = \&__PPIX_TOKENIZER__regexp; sub __PPIX_TOKEN_FALLBACK__regexp { my ( $class, $tokenizer, $character ) = @_; # As a fallback in regexp mode, any escaped character is a literal. if ( $character eq '\\' && $tokenizer->{cursor_limit} - $tokenizer->{cursor_curr} > 1 ) { return $tokenizer->make_token( 2, TOKEN_LITERAL ); } # Any normal character is unknown. return $tokenizer->make_token( 1, TOKEN_UNKNOWN, { error => 'Tokenizer found unexpected literal', }, ); } sub __PPIX_TOKEN_FALLBACK__repl { my ( $class, $tokenizer, $character ) = @_; # As a fallback in replacement mode, any escaped character is a literal. if ( $character eq '\\' && defined ( my $next = $tokenizer->peek( 1 ) ) ) { if ( $tokenizer->interpolates() || $next eq q<'> || $next eq '\\' ) { return $tokenizer->make_token( 2, TOKEN_LITERAL ); } return $tokenizer->make_token( 1, TOKEN_LITERAL ); } # So is any normal character. return $tokenizer->make_token( 1, TOKEN_LITERAL ); } sub __PPIX_TOKENIZER__finish { my ( $class, $tokenizer, $character ) = @_; $tokenizer->{cursor_limit} > length $tokenizer->{content} and confess "Programming error - ran off string"; my @tokens = $tokenizer->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ); if ( $tokenizer->{cursor_curr} eq $tokenizer->{cursor_modifiers} ) { # We are out of string. Make the modifier token and close up # shop. my $trailer; if ( $tokenizer->{content} =~ m/ \s+ \z /smx ) { $tokenizer->{cursor_limit} = $-[0]; $trailer = length( $tokenizer->{content} ) - $tokenizer->{cursor_curr}; } else { $tokenizer->{cursor_limit} = length $tokenizer->{content}; } push @tokens, $tokenizer->make_token( $tokenizer->{cursor_limit} - $tokenizer->{cursor_curr}, 'PPIx::Regexp::Token::Modifier' ); if ( $trailer ) { $tokenizer->{cursor_limit} = length $tokenizer->{content}; push @tokens, $tokenizer->make_token( $trailer, 'PPIx::Regexp::Token::Whitespace' ); } $tokenizer->{mode} = 'kaput'; } else { # Clear the cookies, because we are going around again. $tokenizer->{cookie} = {}; # Move the cursor limit to just before the modifiers. $tokenizer->{cursor_limit} = $tokenizer->{cursor_modifiers} - 1; # If the preceding regular expression was bracketed, we need to # consume possible whitespace and find another delimiter. if ( $tokenizer->close_bracket( $tokenizer->{delimiter_start} ) ) { my $accept; $accept = $tokenizer->find_regexp( qr{ \A \s+ }smx ) and push @tokens, $tokenizer->make_token( $accept, 'PPIx::Regexp::Token::Whitespace' ); my $character = $tokenizer->peek(); $tokenizer->{delimiter_start} = $character; push @tokens, $tokenizer->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ); $tokenizer->{delimiter_finish} = substr $tokenizer->{content}, $tokenizer->{cursor_limit} - 1, 1; $tokenizer->{delimiter_re} = undef; } if ( $tokenizer->modifier( 'e' ) ) { # With /e, 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, $tokenizer->make_token( $tokenizer->{cursor_limit} - $tokenizer->{cursor_curr}, 'PPIx::Regexp::Token::Code', { perl_version_introduced => MINIMUM_PERL }, ); $tokenizer->{cursor_limit} = length $tokenizer->{content}; push @tokens, $tokenizer->make_token( 1, 'PPIx::Regexp::Token::Delimiter' ); push @tokens, $tokenizer->make_token( $tokenizer->{cursor_limit} - $tokenizer->{cursor_curr}, 'PPIx::Regexp::Token::Modifier' ); $tokenizer->{mode} = 'kaput'; } else { # Put our mode to replacement. $tokenizer->{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 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. =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_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 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. =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-2014 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.036/lib/PPIx/Regexp/Util.pm000444000765000765 427012262112576 20163 0ustar00tommessagebus000000000000package 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{ __instance }; our $VERSION = '0.036'; sub __instance { my ( $object, $class ) = @_; blessed( $object ) or return; return $object->isa( $class ); } 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. =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-2014 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.036/lib/PPIx/Regexp/Node000755000765000765 012262112576 17435 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp/Node/Range.pm000444000765000765 271312262112576 21167 0ustar00tommessagebus000000000000=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 }; our $VERSION = '0.036'; 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-2014 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.036/lib/PPIx/Regexp/Structure000755000765000765 012262112576 20550 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp/Structure/Assertion.pm000444000765000765 264612262112576 23222 0ustar00tommessagebus000000000000=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.036'; 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-2014 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.036/lib/PPIx/Regexp/Structure/BranchReset.pm000444000765000765 404312262112576 23444 0ustar00tommessagebus000000000000=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.036'; # 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-2014 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.036/lib/PPIx/Regexp/Structure/Capture.pm000444000765000765 420612262112576 22650 0ustar00tommessagebus000000000000=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.036'; =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-2014 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.036/lib/PPIx/Regexp/Structure/CharClass.pm000444000765000765 436712262112576 23120 0ustar00tommessagebus000000000000=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::Util qw{ __instance }; our $VERSION = '0.036'; 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 ); } =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; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( $self, $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-2014 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.036/lib/PPIx/Regexp/Structure/Code.pm000444000765000765 370612262112576 22123 0ustar00tommessagebus000000000000=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.036'; # 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 ) = @_; 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-2014 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.036/lib/PPIx/Regexp/Structure/Main.pm000444000765000765 533112262112576 22131 0ustar00tommessagebus000000000000=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.036'; =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-2014 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.036/lib/PPIx/Regexp/Structure/Modifier.pm000444000765000765 400412262112576 22777 0ustar00tommessagebus000000000000=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.036'; # 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-2014 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.036/lib/PPIx/Regexp/Structure/NamedCapture.pm000444000765000765 353212262112576 23616 0ustar00tommessagebus000000000000=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.036'; =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-2014 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.036/lib/PPIx/Regexp/Structure/Quantifier.pm000444000765000765 322312262112576 23352 0ustar00tommessagebus000000000000=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 }; our $VERSION = '0.036'; sub can_be_quantified { return; } sub is_quantifier { return 1; } # Called by the lexer to record the capture number. sub __PPIX_LEXER__record_capture_number { my ( $self, $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-2014 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.036/lib/PPIx/Regexp/Structure/Regexp.pm000444000765000765 560612262112576 22504 0ustar00tommessagebus000000000000=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.036'; 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 ); } =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 no arguments. The return is the number of # parse failures discovered when finalizing. sub __PPIX_LEXER__finalize { my ( $self ) = @_; my $rslt = 0; foreach my $elem ( $self->elements() ) { $rslt += $elem->__PPIX_LEXER__finalize(); } # 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-2014 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.036/lib/PPIx/Regexp/Structure/RegexSet.pm000444000765000765 415512262112576 22776 0ustar00tommessagebus000000000000package PPIx::Regexp::Structure::RegexSet; use strict; use warnings; use base qw{ PPIx::Regexp::Structure }; our $VERSION = '0.036'; 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. =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-2014 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.036/lib/PPIx/Regexp/Structure/Replacement.pm000444000765000765 316712262112576 23511 0ustar00tommessagebus000000000000=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.036'; sub can_be_quantified { 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-2014 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.036/lib/PPIx/Regexp/Structure/Subexpression.pm000444000765000765 265012262112576 24117 0ustar00tommessagebus000000000000=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.036'; 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-2014 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.036/lib/PPIx/Regexp/Structure/Switch.pm000444000765000765 557612262112576 22521 0ustar00tommessagebus000000000000=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.036'; sub __PPIX_LEXER__finalize { my ( $self ) = @_; # 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' ); $rslt++; } } 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(); 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-2014 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.036/lib/PPIx/Regexp/Structure/Unknown.pm000444000765000765 260612262112576 22706 0ustar00tommessagebus000000000000=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.036'; 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-2014 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.036/lib/PPIx/Regexp/Token000755000765000765 012262112576 17630 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp/Token/Assertion.pm000444000765000765 573112262112576 22300 0ustar00tommessagebus000000000000=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 the positive look-behind assertion C<\K> added in Perl 5.009005. =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 MINIMUM_PERL TOKEN_LITERAL }; our $VERSION = '0.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { my %perl_version_introduced = ( '\\K' => '5.009005', '\\z' => '5.005', ); sub perl_version_introduced { my ( $self ) = @_; return $perl_version_introduced{$self->content()} || MINIMUM_PERL; } } # 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 ( $class, $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; $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-2014 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.036/lib/PPIx/Regexp/Token/Backreference.pm000444000765000765 1174612262112576 23073 0ustar00tommessagebus000000000000=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 }; our $VERSION = '0.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { 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 = ( # 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 }, ], ); # 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 ) : ( @external ); } sub __PPIX_TOKENIZER__regexp { my ( $class, $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 ) { my ( $re, $arg ) = @{ $_ }; my $accept = $tokenizer->find_regexp( $re ) or next; return $tokenizer->make_token( $accept, __PACKAGE__, $arg ); } return; } sub __PPIX_TOKENIZER__repl { my ( $class, $tokenizer, $character ) = @_; $tokenizer->interpolates() and goto &__PPIX_TOKENIZER__regexp; return; } # 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 \\ \d{2,} \z /smx && $content !~ m/ [89] /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-2014 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.036/lib/PPIx/Regexp/Token/Backtrack.pm000444000765000765 424112262112576 22211 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; 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-2014 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.036/lib/PPIx/Regexp/Token/CharClass.pm000444000765000765 421312262112576 22166 0ustar00tommessagebus000000000000=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.036'; # 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-2014 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.036/lib/PPIx/Regexp/Token/Code.pm000444000765000765 753112262112576 21203 0ustar00tommessagebus000000000000=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.036'; sub _new { my ( $class, $content ) = @_; ref $class and $class = ref $class; my $self = {}; if ( __instance( $content, 'PPI::Document' ) ) { $self->{ppi} = $content; } elsif ( ref $content ) { return; } else { $self->{content} = $content; } bless $self, $class; 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 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. =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 }; { my %default = ( perl_version_introduced => '5.005', # When (?{...}) introduced. ); sub __PPIX_TOKEN__post_make { my ( $self, $tokenizer, $arg ) = @_; $self->__impose_defaults( $arg, \%default ); # If we're manufacturing objects directly (which is UNSUPPORTED, # but used in t/version.t) we may not have a $tokenizer. $tokenizer and $tokenizer->cookie( COOKIE_REGEX_SET ) and $self->__error( 'Code token not valid in Regex set' ); return; } } sub __PPIX_TOKENIZER__regexp { my ( $class, $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-2014 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.036/lib/PPIx/Regexp/Token/Comment.pm000444000765000765 451412262112576 21731 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; sub significant { return; } sub comment { return 1; } # 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-2014 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.036/lib/PPIx/Regexp/Token/Condition.pm000444000765000765 546112262112576 22257 0ustar00tommessagebus000000000000=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.036'; 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 ( $class, $tokenizer, $character ) = @_; 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-2014 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.036/lib/PPIx/Regexp/Token/Control.pm000444000765000765 712712262112576 21752 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { 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 = ( Q => sub { return 1; }, E => undef, ); sub __PPIX_TOKENIZER__regexp { my ( $class, $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 ); my $reject = $in_quote ? sub { my ( $size, $class ) = @_; return $tokenizer->make_token( $size, $class || TOKEN_LITERAL ); } : sub { return; }; # 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 ); # If we are quoting, we reject anything but an end quote. $in_quote and $control ne 'E' and 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 ); # \Q and \E make and destroy cookies respectively; do those things. exists $cookie{$control} and $tokenizer->cookie( COOKIE_QUOTE, $cookie{$control} ); # Return our token. return $token; } sub __PPIX_TOKENIZER__repl { my ( $class, $tokenizer, $character ) = @_; $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-2014 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.036/lib/PPIx/Regexp/Token/Delimiter.pm000444000765000765 313512262112576 22243 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { 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-2014 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.036/lib/PPIx/Regexp/Token/Greediness.pm000444000765000765 443712262112576 22423 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; 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 ( $class, $string ) = @_; return $greediness{$string}; } sub perl_version_introduced { my ( $self ) = @_; return $greediness{ $self->content() } || MINIMUM_PERL; } sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character, $char_type ) = @_; $tokenizer->prior( '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-2014 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.036/lib/PPIx/Regexp/Token/GroupType.pm000444000765000765 1253012262112576 22302 0ustar00tommessagebus000000000000=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 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.036'; # 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. =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 %rslt; foreach my $str ( $class->__defining_string() ) { my %seen; my @chars = grep { ! $seen{$_}++ } split qr{}smx, $str; 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 ) = @_; 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-2014 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.036/lib/PPIx/Regexp/Token/Interpolation.pm000444000765000765 3045312262112576 23177 0ustar00tommessagebus000000000000=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 no 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 PPI::Document; use PPIx::Regexp::Constant qw{ COOKIE_CLASS COOKIE_REGEX_SET TOKEN_LITERAL MINIMUM_PERL }; our $VERSION = '0.036'; # 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, $character, $in_regexp ) = @_; # 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 $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' ) ) { =begin comment local $_ = $next->content(); if ( m< \A { / } >smx ) { push @accum, 3; # Number of characters to accept. } else { ## $allow_subscript = $accum[-1]->content() ne '$#'; push @accum, $next; } =end comment =cut 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; } # 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; } { 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. sub _curly { my ( $class, @kids ) = @_; # 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 we have exactly one child which is a symbol, we accept it as a # subscript. @kids == 1 and $kids[0]->isa( 'PPI::Token::Symbol' ) 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. sub _square { my ( $class, @kids ) = @_; # 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; } { my %default = ( perl_version_introduced => MINIMUM_PERL, ); sub __PPIX_TOKEN__post_make { my ( $self, $tokenizer, $arg ) = @_; # If we're manufacturing objects directly (which is UNSUPPORTED, # but used in t/version.t) we may not have a $tokenizer. $tokenizer and $tokenizer->cookie( COOKIE_REGEX_SET ) and $self->{perl_version_introduced} = '5.017009'; $self->__impose_defaults( $arg, \%default ); 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 = _interpolation( $class, $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 = _interpolation( $class, $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-2014 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.036/lib/PPIx/Regexp/Token/Literal.pm000444000765000765 2760112262112576 21745 0ustar00tommessagebus000000000000=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 MINIMUM_PERL TOKEN_UNKNOWN }; our $VERSION = '0.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; 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 ); } # 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'; $white_space_re = eval $white_space_re; ## no critic (ProhibitStringyEval) my %regex_pass_on = map { $_ => 1 } qw{ [ ] ( ) $ \ }; sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character, $char_type ) = @_; 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; $accept = $tokenizer->find_regexp( $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' ); } 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. 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 ) ) { 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; } } { 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 ); } } *__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-2014 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.036/lib/PPIx/Regexp/Token/Modifier.pm000444000765000765 2733112262112576 22107 0ustar00tommessagebus000000000000=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. B that if this is retracted before Perl 5.14 is released, this support will disappear. See L for some explanation. =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 PPIx::Regexp::Constant qw{ MINIMUM_PERL MODIFIER_GROUP_MATCH_SEMANTICS }; our $VERSION = '0.036'; # 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}++; } =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)>. 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 ) = @_; my $bin = $aggregate{$modifier} or return $present->{$modifier}; return defined $present->{$bin} && $modifier eq $present->{$bin}; } sub can_be_quantified { return }; =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(); # 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. $content = join '', sort 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 { $present{$1} = $value; } } } 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 ], ); } # After the token is made, figure out what it asserts or negates. sub __PPIX_TOKEN__post_make { my ( $self, $tokenizer ) = @_; defined $tokenizer and $tokenizer->modifier_modify( $self->modifiers() ); return; } { # 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-2014 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.036/lib/PPIx/Regexp/Token/Operator.pm000444000765000765 543412262112576 22124 0ustar00tommessagebus000000000000=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{ TOKEN_LITERAL }; use PPIx::Regexp::Util qw{ __instance }; our $VERSION = '0.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; # 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' ); } sub __PPIX_TOKENIZER__regexp { my ( $class, $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() ) 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-2014 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.036/lib/PPIx/Regexp/Token/Quantifier.pm000444000765000765 422412262112576 22434 0ustar00tommessagebus000000000000=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 }; our $VERSION = '0.036'; # 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 ( $class, $string ) = @_; return $quantifier{$string}; } sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; $tokenizer->prior( '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-2014 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.036/lib/PPIx/Regexp/Token/Recursion.pm000444000765000765 432712262112576 22302 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; 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-2014 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.036/lib/PPIx/Regexp/Token/Reference.pm000444000765000765 1203712262112576 22244 0ustar00tommessagebus000000000000=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.036'; =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; } # Called after the token is manufactured. The calling sequence is # $token->__PPIX_TOKEN__post_make( $tokenizer, $arg ); # For the sake of reblessing into this class, we are expected to deal # with the situation where the optional argument is missing. sub __PPIX_TOKEN__post_make { my ( $self, $tokenizer, $arg ) = @_; my $capture; if ( defined $arg ) { $tokenizer and $capture = first { defined $_ } $tokenizer->capture(); defined $capture or $capture = $arg->{capture}; } else { my $content = $self->content(); foreach ( $self->__PPIX_TOKEN__recognize() ) { my ( $re, $a ) = @{ $_ }; $content =~ $re or next; $arg = $a; if ( exists $arg->{capture} ) { $capture = $arg->{capture}; } else { foreach my $inx ( 1 .. $#- ) { defined $-[$inx] or next; $capture = substr $content, $-[$inx], $+[$inx] - $-[$inx]; last; } } last; } } defined $capture or confess q{Programming error - reference '}, $self->content(), q{' of unknown form}; foreach my $key ( keys %{ $arg } ) { $key eq 'capture' and next; $self->{$key} = $arg->{$key}; } if ( $arg->{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; }; 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-2014 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.036/lib/PPIx/Regexp/Token/Structure.pm000444000765000765 2342212262112576 22346 0ustar00tommessagebus000000000000=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.036'; # 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() }; }; 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 ( $class, $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 ); } # 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', ); # 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( '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( '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( '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-2014 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.036/lib/PPIx/Regexp/Token/Unknown.pm000444000765000765 502112262112576 21760 0ustar00tommessagebus000000000000=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 }; our $VERSION = '0.036'; # 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_TOKEN__post_make { my ( $self, $tokenizer, $arg ) = @_; my $msg = $arg->{error}; use Carp; defined $msg or Carp::cluck( 'Making unknown token with no error message' ); defined $msg or $msg = 'Unspecified error'; $self->{error} = $msg; return; } # 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-2014 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.036/lib/PPIx/Regexp/Token/Unmatched.pm000444000765000765 324412262112576 22236 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { 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-2014 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.036/lib/PPIx/Regexp/Token/Whitespace.pm000444000765000765 560012262112576 22420 0ustar00tommessagebus000000000000=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 /x 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). =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 }; use PPIx::Regexp::Constant qw{ COOKIE_REGEX_SET MINIMUM_PERL }; our $VERSION = '0.036'; sub perl_version_introduced { my ( $self ) = @_; return $self->{perl_version_introduced}; } sub significant { return; } sub whitespace { return 1; } # Return true if the token can be quantified, and false otherwise sub can_be_quantified { return }; # 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. =begin comment sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; return scalar $tokenizer->find_regexp( qr{ \A \s+ }smx ); } =end comment =cut sub __PPIX_TOKEN__post_make { my ( $self, $tokenizer, $arg ) = @_; $self->{perl_version_introduced} = MINIMUM_PERL; # RT #91798. # TODO the above needs to be replaced by the following (suitably # modified) when the non-ASCII white space characters are finally # recognized by Perl. =begin comment if ( ord $self->content() < 128 ) { $self->{perl_version_introduced} = MINIMUM_PERL; } elsif ( $tokenizer && $tokenizer->cookie( COOKIE_REGEX_SET ) ) { $self->{perl_version_introduced} = '5.017008'; } else { $self->{perl_version_introduced} = '5.017009'; } =end comment =cut 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-2014 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.036/lib/PPIx/Regexp/Token/CharClass000755000765000765 012262112576 21473 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp/Token/CharClass/POSIX.pm000444000765000765 577112262112576 23102 0ustar00tommessagebus000000000000=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.036'; # 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 %class = ( ':' => __PACKAGE__, ); sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; $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-2014 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.036/lib/PPIx/Regexp/Token/CharClass/Simple.pm000444000765000765 1165012262112576 23442 0ustar00tommessagebus000000000000=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 MINIMUM_PERL TOKEN_LITERAL TOKEN_UNKNOWN }; our $VERSION = '0.036'; ##=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; } } sub __PPIX_TOKENIZER__regexp { my ( $class, $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-]+ \} ) }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-2014 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.036/lib/PPIx/Regexp/Token/CharClass/POSIX000755000765000765 012262112576 22375 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp/Token/CharClass/POSIX/Unknown.pm000444000765000765 433712262112576 24536 0ustar00tommessagebus000000000000package 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.036'; 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-2014 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.036/lib/PPIx/Regexp/Token/GroupType000755000765000765 012262112576 21566 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/lib/PPIx/Regexp/Token/GroupType/Assertion.pm000444000765000765 356612262112576 24242 0ustar00tommessagebus000000000000=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.036'; { 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-2014 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.036/lib/PPIx/Regexp/Token/GroupType/BranchReset.pm000444000765000765 324012262112576 24460 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; 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-2014 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.036/lib/PPIx/Regexp/Token/GroupType/Code.pm000444000765000765 572012262112576 23137 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; { 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 ( $class, $tokenizer ) = @_; $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-2014 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.036/lib/PPIx/Regexp/Token/GroupType/Modifier.pm000444000765000765 614512262112576 24025 0ustar00tommessagebus000000000000=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.036'; { 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-2014 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.036/lib/PPIx/Regexp/Token/GroupType/NamedCapture.pm000444000765000765 645712262112576 24645 0ustar00tommessagebus000000000000=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.036'; use constant NAMED_CAPTURE => qr{ \A \\? \? (?: P? < ( @{[ RE_CAPTURE_NAME ]} ) \\? > | \\? ' ( @{[ RE_CAPTURE_NAME ]} ) \\? ' ) }smxo; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; =head2 name This method returns the name of the capture. =cut sub name { my ( $self ) = @_; return $self->{name}; } sub perl_version_introduced { return '5.009005'; } sub __PPIX_TOKEN__post_make { my ( $self, $tokenizer ) = @_; if ( $tokenizer ) { foreach my $name ( $tokenizer->capture() ) { defined $name or next; $self->{name} = $name; return; } } else { foreach my $name ( $self->content() =~ m/ @{[ NAMED_CAPTURE ]} /smxo ) { defined $name or next; $self->{name} = $name; return; } } confess 'Programming error - can not figure out capture name'; } =begin comment sub __PPIX_TOKENIZER__regexp { my ( $class, $tokenizer, $character ) = @_; # The optional escapes are because any of the non-open-bracket # punctuation characters may be the expression delimiter. if ( my $accept = $tokenizer->find_regexp( NAMED_CAPTURE ) ) { return $accept; } return; } =end comment =cut 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-2014 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.036/lib/PPIx/Regexp/Token/GroupType/Subexpression.pm000444000765000765 326712262112576 25142 0ustar00tommessagebus000000000000=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.036'; # Return true if the token can be quantified, and false otherwise # sub can_be_quantified { return }; sub perl_version_introduced { my ( $self ) = @_; 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-2014 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.036/lib/PPIx/Regexp/Token/GroupType/Switch.pm000444000765000765 460712262112576 23531 0ustar00tommessagebus000000000000=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.036'; 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 ( $class, $tokenizer ) = @_; $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-2014 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.036/LICENSES000755000765000765 012262112576 15135 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/LICENSES/Artistic000444000765000765 1373712262112576 17032 0ustar00tommessagebus000000000000 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.036/LICENSES/Copying000444000765000765 3053012262112576 16646 0ustar00tommessagebus000000000000 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.036/t000755000765000765 012262112576 14173 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/t/basic.t000444000765000765 2541412262112576 15624 0ustar00tommessagebus000000000000package main; use strict; use warnings; use Test::More 0.88; 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::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( 'xyzzy' ), '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' ), '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( 'xyzzy' ), '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' ), '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' ), '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' ), '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' ), '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' ), 'PPIx::Regexp::Token::Modifier' ); require_ok( 'PPIx::Regexp::Token::Operator' ); class_isa_ok( 'PPIx::Regexp::Token::Operator', 'PPIx::Regexp::Token' ); isa_ok( PPIx::Regexp::Token::Operator->_new( 'xyzzy' ), '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( 'xyzzy' ), 'PPIx::Regexp::Token::Recursion' ); require_ok( 'PPIx::Regexp::Token::Reference' ); class_isa_ok( 'PPIx::Regexp::Token::Reference', 'PPIx::Regexp::Token' ); 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' ), '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' ); 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' ); 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.036/t/parse.t000444000765000765 101240312262112576 15710 0ustar00tommessagebus000000000000package main; use strict; use warnings; use lib qw{ inc }; use PPIx::Regexp::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 ( '' ); 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::Interpolation' ); 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::Interpolation' ); 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 ( '' ); done_testing; 1; # ex: set textwidth=72 : PPIx-Regexp-0.036/t/unit.t000444000765000765 13704112262112576 15542 0ustar00tommessagebus000000000000package main; use strict; use warnings; use lib qw{ inc }; use PPI::Document; use PPIx::Regexp::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' ); { # 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 ); 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" ); SKIP: { $is_ascii or skip( 'Non-ASCII machines will have different ordinal values', 10, ); 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 PPIx::Regexp::Token::Structure '' significant PPIx::Regexp::Structure::Regexp / ... / 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.036/t/version.t000444000765000765 10213512262112576 16244 0ustar00tommessagebus000000000000# 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.006002; 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. # Trailing empty fields are removed. use PPIx::Regexp::Constant qw{ 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; 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'; method perl_version_introduced => '5.006'; method perl_version_removed => undef; 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}'; method perl_version_introduced => '5.005'; # see ::GroupType::Code 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; 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; 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 '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::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 '^', note => 'Character class inversion'; method perl_version_introduced => MINIMUM_PERL, note => '5.3.7 perlre'; method perl_version_removed => undef; token '-', 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. =begin comment 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.017009', note => 'perl5179delta'; method perl_version_removed => undef; } =end comment =cut class 'PPIx::Regexp::Token::Structure', note => 'Regex set'; token '(?['; method perl_version_introduced => '5.017008', note => 'perl5178delta'; 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; $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 $title = "Instantiate $context->{class}{class} with '$content'"; if ( eval { my $obj = $context->{class}{class}->_new( $content ); my $tokenizer; if ( my $cookie = delete $args{cookie} ) { $tokenizer = PPIx::Regexp::Tokenizer->new( $content ); $tokenizer->cookie( $cookie => sub { 1 } ); } $obj->can( '__PPIX_TOKEN__post_make' ) and $obj->__PPIX_TOKEN__post_make( $tokenizer ); $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.036/xt000755000765000765 012262112576 14363 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/xt/author000755000765000765 012262112576 15665 5ustar00tommessagebus000000000000PPIx-Regexp-0.036/xt/author/changes.t000444000765000765 60212262112576 17575 0ustar00tommessagebus000000000000package 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.036/xt/author/critic.t000444000765000765 53612262112576 17450 0ustar00tommessagebus000000000000package 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.036/xt/author/executable.t000444000765000765 111412262112576 20325 0ustar00tommessagebus000000000000package 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.036/xt/author/kwalitee.t000444000765000765 53212262112576 17774 0ustar00tommessagebus000000000000package 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.036/xt/author/manifest.t000444000765000765 116212262112576 20015 0ustar00tommessagebus000000000000package 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.036/xt/author/perlcriticrc000444000765000765 351412262112576 20435 0ustar00tommessagebus000000000000severity = 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::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 = 1 severity = stern PPIx-Regexp-0.036/xt/author/pod.t000444000765000765 45312262112576 16753 0ustar00tommessagebus000000000000package 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.036/xt/author/pod_spelling.t000444000765000765 111112262112576 20660 0ustar00tommessagebus000000000000package 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__ charnames errstr indices instantiation lexed lexes merchantability nav navigational perluniprops POSIX PPI ppi PPI's reblesses repl schild schildren subclasses TODO tokenization Tokenize tokenize tokenized tokenizer's TOKENIZERS tokenizers tokenizes tokenizing trigraphs unicode unterminated UTF version's Wyant XS