use 5.010; use warnings; use Test::More 'no_plan'; # Use this class declaration to check that classes with ctors # actually call the ctor when objrules use them... { package file; sub new { my ($class, $data_ref) = @_; my $new_obj = bless {'check'=>'check',%{$data_ref}}, $class; return $new_obj; } } my $parser = do{ use Regexp::Grammars; qr{ <[element]>* | \\ ? ? \[ <[option]> ** (,) \] \{ <[element]>* \} [^][\$&%#_{}~^\s,]+ [^][\$&%#_{}~^\s]+ }xms }; my $target = { "file" => bless({ "check" => "check", "element" => [ bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "article", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "documentclass", }, "literal"), "options" => bless({ "option" => [ bless({ "" => "a4paper", }, "option"), bless({ "" => "11pt", }, "option"), ], }, "options"), }, "command"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "latexsym", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "usepackage", }, "literal"), }, "command"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "D.", }, "literal"), }, "element"), bless({ "literal" => bless({ "" => "Conway", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "author", }, "literal"), }, "command"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "Parsing", }, "literal"), }, "element"), bless({ "command" => bless({ "args" => bless({ "" => "{}", }, "args"), "name" => bless({ "" => "LaTeX", }, "literal"), }, "command"), }, "element"), ], }, "args"), "name" => bless({ "" => "title", }, "literal"), }, "command"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "document", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "begin", }, "literal"), }, "command"), }, "element"), bless({ "command" => bless({ "name" => bless({ "" => "maketitle", }, "literal"), }, "command"), }, "element"), bless({ "command" => bless({ "name" => bless({ "" => "tableofcontents", }, "literal"), }, "command"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "Description", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "section", }, "literal"), }, "command"), }, "element"), bless({ "literal" => bless({ "" => "...is", }, "literal"), }, "element"), bless({ "literal" => bless({ "" => "easy", }, "literal"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "But", }, "literal"), }, "element"), bless({ "literal" => bless({ "" => "not", }, "literal"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "necessarily", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "emph", }, "literal"), }, "command"), }, "element"), bless({ "literal" => bless({ "" => "simple", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "footnote", }, "literal"), }, "command"), }, "element"), bless({ "literal" => bless({ "" => ".", }, "literal"), }, "element"), bless({ "command" => bless({ "args" => bless({ "element" => [ bless({ "literal" => bless({ "" => "document", }, "literal"), }, "element"), ], }, "args"), "name" => bless({ "" => "end", }, "literal"), }, "command"), }, "element"), ], }, "file"), }; my $input = do{ local $/; }; chomp $input; my $original_input = $input; ok +($input =~ $parser) => 'Matched'; is_deeply \%/, $target => 'Returned correct data structure'; ok !exists $/{""} => 'Entire text not captured'; __DATA__ \documentclass[a4paper,11pt]{article} \usepackage{latexsym} \author{D. Conway} \title{Parsing \LaTeX{}} \begin{document} \maketitle \tableofcontents \section{Description} ...is easy \footnote{But not \emph{necessarily} simple}. \end{document}