1 package WebPAC::Parser;
9 use Data::Dump qw/dump/;
12 use base qw/WebPAC::Common WebPAC::Normalize/;
16 WebPAC::Parser - parse perl normalization configuration files and mungle it
24 our $VERSION = '0.03';
34 Create new parser object.
36 my $parser = new WebPAC::Parser(
37 config => new WebPAC::Config(),
38 base_path => '/optional/path/to/conf',
48 my $log = $self->_get_logger();
50 $log->logdie("config isn't WebPAC::Config") unless ($self->{config} && $self->{config}->isa('WebPAC::Config'));
52 $log->logdie("can't iterate_inputs over this config object") unless ($self->{config}->can('iterate_inputs'));
56 $self->{config}->iterate_inputs( sub {
57 my ($input, $database) = @_;
58 return unless $self->valid_database_input($database, $input->{name});
59 $self->parse_lookups($database,$input->{name});
62 $self ? return $self : return undef;
67 my $source_files = $parser->read_sources;
76 my $log = $self->_get_logger();
80 $self->{config}->iterate_inputs( sub {
81 my ($input, $database) = @_;
83 my $path = $input->{normalize}->{path} || return;
84 my $full = $self->{base_path} ? $self->{base_path} . '/' . $path : $path;
86 $log->logdie("normalization input $full doesn't exist") unless (-e $full);
88 my $s = read_file( $full ) || $log->logdie("can't read $full: $!");
90 my $input_name = $input->{name} || $log->logdie("can't deduce name of input: ", dump( $input ));
92 $log->debug("$database/$input_name: adding $path");
94 $self->{valid_inputs}->{$database}->{$input_name} = {
98 } unless defined($self->{valid_inputs}->{$database}->{$input_name});
100 $self->{valid_inputs}->{$database}->{$input_name}->{usage}++;
105 $log->debug("found $nr source files");
112 $parser->parse_lookups($database,$input);
118 my ($database, $input) = @_;
120 my $log = $self->_get_logger();
122 $log->logdie("invalid database $database" ) unless $self->valid_database( $database );
123 $log->logdie("invalid input $input of database $database", ) unless $self->valid_database_input( $database, $input );
125 my $source = $self->{valid_inputs}->{$database}->{$input}->{source};
126 my $path = $self->{valid_inputs}->{$database}->{$input}->{path};
128 $log->logdie("no source found for database $database input $input path $path") unless ($source);
130 $log->info("parsing lookups for $database/$input from $path");
132 my $Document = PPI::Document->new( \$source ) || $log->logdie("can't parse source:\n", $self->{source});
134 $Document->prune('PPI::Token::Whitespace');
135 #$Document->prune('PPI::Token::Operator');
137 # Find all the named subroutines
139 $self->{_lookup_errors} = ();
144 $self->_get_logger->logconfess("error without message?") unless ($msg);
145 push @{ $self->{_lookup_errors} }, $msg;
149 $Document->find( sub {
150 my ($Document,$Element) = @_;
152 $Element->isa('PPI::Token::Word') or return '';
153 $Element->content eq 'lookup' or return '';
155 $log->debug("expansion: ", $Element->snext_sibling);
157 my $args = $Element->snext_sibling;
159 my @e = $args->child(0)->elements;
160 $log->logdie("hum, expect at least 8 elements, got ", scalar @e, " in $args") if ($#e < 8);
162 if ($log->is_debug) {
163 my $report = "found " . scalar @e . " elements:\n";
165 foreach my $i ( 0 .. $#e ) {
166 $report .= sprintf("# %-2d: %-30s %s\n", $i, ( $e[$i] || 'undef' ), $e[$i]->class );
169 $log->debug($report);
172 my $key_element = $e[8]->clone;
174 $log->logdie("key element must be PPI::Structure::Block") unless $key_element->isa('PPI::Structure::Block');
176 $log->debug("key part: ", $key_element);
180 $key_element->find( sub {
181 my $e = $_[1] || die "no element?";
182 $e->isa('PPI::Token::Word') or return '';
183 $e->content eq 'rec' or return '';
185 my $kf = $e->snext_sibling;
187 $log->debug("key fragment = $kf");
190 $log->logdie("can't eval { $kf }: $@") if ($@);
195 my $key = join('-', @key ) || $log->logdie("no key found!");
197 $log->debug("key = $key");
200 $coderef = ' . $e[7] . $e[8] . ';
201 foreach my $v ($coderef->()) {
202 next unless (defined($v) && $v ne \'\');
203 push @{ $lookup->{\'' . $key . '\'}->{$v} }, $mfn;
207 $log->debug("create: $create");
209 return $self->_lookup_error("invalid database $e[3] in $path" ) unless $self->valid_database( $e[3] );
210 return $self->_lookup_error("invalid input $e[5] of database $e[3] in $path", ) unless $self->valid_database_input( $e[3], $e[5] );
212 $self->add_lookup_create( $e[3], $e[5], $create );
215 $e[8]->insert_after( $e[8]->clone );
216 $e[8]->insert_after( $e[7]->clone );
217 $e[8]->insert_after( $e[6]->clone );
221 $e[8]->insert_before( new PPI::Token::Quote::Single( "'$key'" ) );
225 $log->debug(">>> ", $Element->snext_sibling);
228 my $normalize_source = $Document->serialize;
229 $log->debug("create: ", dump($self->{_lookup_create}) );
230 $log->debug("normalize: $normalize_source");
232 $self->{_normalize_source}->{$database}->{$input} = $normalize_source;
234 if ($self->{debug}) {
235 my $Dumper = PPI::Dumper->new( $Document );
239 $log->error("Parser errors:\n", join("\n",@{ $self->{_lookup_errors} }) ) if ($self->{_lookup_errors});
244 =head2 add_lookup_create
246 $parse->add_lookup_create($database,$input,$source);
250 sub add_lookup_create {
252 my ($database,$input,$source) = @_;
253 $self->{_lookup_create}->{$database}->{$input} .= $source;
257 =head2 valid_database
259 my $ok = $parse->valid_database('key');
266 my $database = shift || return;
267 $database =~ s/['"]//g;
269 return defined($self->{valid_inputs}->{$database});
272 =head2 valid_database_input
274 my $ok = $parse->valid_database('database_key','input_name');
278 sub valid_database_input {
281 my ($database,$input) = @_;
282 $database =~ s/['"]//g;
285 return defined($self->{valid_inputs}->{$database}->{$input});
290 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
292 =head1 COPYRIGHT & LICENSE
294 Copyright 2006 Dobrica Pavlinusic, All Rights Reserved.
296 This program is free software; you can redistribute it and/or modify it
297 under the same terms as Perl itself.
301 1; # End of WebPAC::Parser