File Coverage

blib/lib/Logic/Expr/Parser.pm
Criterion Covered Total %
statement 29 29 100.0
branch 6 6 100.0
condition 3 3 100.0
subroutine 10 10 100.0
pod 4 4 100.0
total 52 52 100.0


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             #
3             # a parser for logic expressions
4              
5             package Logic::Expr::Parser;
6             our $VERSION = '0.01';
7 3     3   605072 use Logic::Expr ':all';
  3         7  
  3         425  
8 3     3   16 use base 'Parser::MGC'; # 0.21 or higher required
  3         4  
  3         1272  
9              
10             # LE_NOT is handled outside the scope of this pair of variables
11             our %le_map = (
12             '&' => LE_AND,
13             '|' => LE_OR,
14             'v' => LE_OR,
15             '->' => LE_COND,
16             '==' => LE_BICOND,
17             );
18             our $le_regex = qr/->|==|[&|v]/;
19              
20             sub on_parse_start
21             {
22 14     14 1 25054 my ($self) = @_;
23             # hopefully these never conflict with Parser::MGC internals
24 14         47 @$self{qw(_atoms _bools)} = ( {}, [] );
25             }
26              
27             sub on_parse_end
28             {
29 9     9 1 222 my ( $self, $tree ) = @_;
30             Logic::Expr->new(
31             atoms => $self->{_atoms},
32             bools => $self->{_bools},
33 9         36 expr => $tree
34             );
35             }
36              
37             sub parse
38             {
39 17     17 1 198 my ($self) = @_;
40 17         38 my $first = $self->parse_term;
41 14         20 my ( $operator, $second );
42             $self->maybe(
43             sub {
44 14     14   133 $operator = $le_map{ $self->expect($le_regex) };
45 11         476 $second = $self->parse_term;
46             }
47 14         95 );
48 14 100       235 defined $operator ? [ $operator, $first, $second ] : $first;
49             }
50              
51             sub parse_term
52             {
53 28     28 1 42 my ($self) = @_;
54 28     28   100 my $neg = $self->maybe( sub { $self->expect(qr/!+|~+/) } );
  28         338  
55             my $term = $self->any_of(
56 28     28   341 sub { $self->scope_of( "(", \&parse, ")" ) },
57             sub {
58 25     25   1698 my $atom = $self->expect(qr/[A-Z]+/);
59 22 100       886 unless ( exists $self->{_atoms}->{$atom} ) {
60 21         25 push @{ $self->{_bools} }, TRUE;
  21         38  
61 21         45 $self->{_atoms}->{$atom} = \$self->{_bools}->[-1];
62             }
63 22         79 $self->{_atoms}->{$atom};
64             },
65 28         1886 );
66             # simplify !!!X to !X and !!X to X
67 25 100 100     229 ( defined $neg and length($neg) & 1 ) ? [ LE_NOT, $term ] : $term;
68             }
69              
70             1;
71             __END__