File Coverage

blib/lib/Parse/RandGen/Grammar.pm
Criterion Covered Total %
statement 36 88 40.9
branch 12 66 18.1
condition 3 15 20.0
subroutine 8 15 53.3
pod 5 10 50.0
total 64 194 32.9


line stmt bran cond sub pod time code
1             # $Revision: #3 $$Date: 2005/08/31 $$Author: jd150722 $
2             ######################################################################
3             #
4             # This program is Copyright 2003-2005 by Jeff Dutton.
5             #
6             # This program is free software; you can redistribute it and/or modify
7             # it under the terms of either the GNU General Public License or the
8             # Perl Artistic License.
9             #
10             # This program is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13             # GNU General Public License for more details.
14             #
15             # If you do not have a copy of the GNU General Public License write to
16             # the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
17             # MA 02139, USA.
18             ######################################################################
19              
20             package Parse::RandGen::Grammar;
21              
22             require 5.006_001;
23 4     4   20 use Carp;
  4         8  
  4         240  
24 4     4   22 use Data::Dumper;
  4         10  
  4         178  
25 4     4   24 use Parse::RandGen qw($Debug);
  4         7  
  4         436  
26 4     4   21 use strict;
  4         6  
  4         208  
27 4     4   22 use vars qw($Debug);
  4         5  
  4         5490  
28              
29             ######################################################################
30             #### Creators
31              
32             sub new {
33 1     1 1 17 my $class = shift;
34 1         7 my $self = {
35             _name => undef, # Name of the grammar
36             _rules => { }, # Rules of the grammar
37             _examples => { }, # Examples for various rules in the grammar
38             #@_,
39             };
40 1   33     8 bless $self, ref($class)||$class;
41              
42 1 50       10 $self->{_name} = shift or confess("%Error: Cannot call new without a name for the new grammer (only required argument)!");
43 1         3 return($self);
44             }
45              
46             ######################################################################
47             #### Methods
48              
49             # Add Rules to the Grammar
50             sub addRule {
51 1     1 0 2 my $expType = "Parse::RandGen::Rule";
52 1 50       4 my $self = shift or confess("%Error: Cannot call without a valid object!");
53 1 50       4 my $rule = shift or confess("%Error: addRule takes a required $expType object!");
54 1 50       5 confess("%Error: Passed a ".ref($rule)." argument instead of a $expType reference argument!") unless (ref($rule) eq $expType);
55 1 50       6 confess("%Error: Overwriting the existing rule for ", $rule->name(), "!") if exists($self->{_rules}{$rule->name()});
56 1 50 33     5 confess("%Error: Passed a Rule that already belongs to a different Grammar object!\n") if (defined($rule->grammar()) && ($rule->grammar() != $self));
57 1         5 $self->{_rules}{$rule->name()} = $rule; # Save the rule in the _rule hash
58 1         3 $rule->{_grammar} = $self; # Set the rule's grammar to self
59             }
60              
61             # Add examples for a particular Rule to the Grammar
62             sub addExamples {
63 0 0   0 0 0 my $self = shift or confess("%Error: Cannot call without a valid object!");
64 0 0       0 my $ruleName = shift or confess("%Error: Cannot call without a rule name!");
65 0 0       0 (ref($ruleName) eq "") or confess("%Error: Argument given for a rule name is actually a ".ref($ruleName)." reference!");
66 0 0       0 ($self->rule($ruleName)) or confess("%Error: Cannot find the $ruleName rule on this grammar!");
67 0         0 my @examples = @_;
68              
69 0 0       0 if (!defined($self->{_examples}{$ruleName})) {
70 0         0 $self->{_examples}{$ruleName} = [ ]; # List of examples for the given rule
71             }
72 0         0 my $exList = $self->{_examples}{$ruleName};
73 0         0 foreach my $example (@examples) {
74 0 0       0 (ref($example) eq "HASH") or confess("%Error: Example argument should be a HASH reference with \"stat\" and \"val\" entries, but is actually a ".ref($example)." reference!");
75 0 0 0     0 (defined($example->{stat}) && defined($example->{val})) or confess("%Error: Example hash does not contain both \"stat\" and \"val\" entries!");
76 0         0 push @$exList, $example;
77             }
78             }
79              
80             # Check the Grammar for completeness/errors
81             sub check {
82 0 0   0 0 0 my $self = shift or confess("%Error: Cannot call without a valid object!");
83 0         0 my $grammarName = $self->name();
84              
85 0         0 my $err = "";
86 0         0 foreach my $ruleName (keys %{$self->{_rules}}) {
  0         0  
87 0         0 my $rule = $self->rule($ruleName);
88 0         0 $err .= $rule->check();
89             }
90 0         0 return $err;
91             }
92              
93             # Dump the Grammar
94             sub dump {
95 0 0   0 1 0 my $self = shift or confess("%Error: Cannot call without a valid object!");
96 0         0 my $output = "";
97 0 0       0 if ($Debug) {
98 0         0 my $d = Data::Dumper->new([$self]);
99 0         0 $d->Terse(1);
100 0         0 $output .= $self->name() . " = " . $d->Dump();
101             } else {
102 0         0 $output .= "#" . $self->name() . " Grammar specification:\n";
103             #$output .= "\n";
104 0         0 my @ruleNames = sort keys %{$self->{_rules}};
  0         0  
105 0         0 foreach my $ruleName (@ruleNames) {
106 0         0 $output .= $self->rule($ruleName)->dump();
107             }
108 0 0       0 $output .= "# No rules defined...\n" if ($#ruleNames < 0);
109             }
110 0         0 return $output;
111             }
112              
113             ######################################################################
114             #### Accessors
115              
116             sub name {
117 0 0   0 1 0 my $self = shift or confess("%Error: Cannot call name() without a valid object!");
118 0         0 return $self->{_name};
119             }
120              
121             sub rule { # Access the named rule (no side effects: undef is returned if the rule is not found)
122 0 0   0 1 0 my $self = shift or confess("%Error: Cannot call rule() without a valid object!");
123 0 0       0 my $name = shift or confess("%Error: Cannot call rule() without the name of the Rule to find!");
124 0 0 0     0 if (exists($self->{_rules}{$name}) && !defined($self->{_rules}{$name})) { die "Grammar has a rule \"$name\", which references an undefined Rule object!\n"; }
  0         0  
125 0 0       0 my $rule = $self->{_rules}{$name} if exists($self->{_rules}{$name});
126 0         0 return $rule;
127             }
128              
129             sub defineRule { # Access the named rule (if it does not exist, create the rule)
130 1 50   1 1 15 my $self = shift or confess("%Error: Cannot call defineRule() without a valid object!");
131 1 50       4 my $name = shift or confess("%Error: Cannot call defineRule() without the name of the Rule to find!");
132 1 50 33     7 exists($self->{_rules}{$name}) and not defined($self->{_rules}{$name}) and die ($self->name() . " Grammar has a rule \"$name\", which references an undefined Rule object!\n");
133 1 50       5 exists($self->{_rules}{$name}) and confess($self->name() . "Grammar already has a definition for the \"$name\" rule!\n");
134 1 50       5 if (!exists($self->{_rules}{$name})) {
135 1         11 $self->addRule(Parse::RandGen::Rule->new($name));
136             }
137 1 50       5 my $rule = $self->{_rules}{$name} or die "%Error: Failed to create the \"$name\" rule!";
138 1         11 return $rule;
139             }
140              
141             sub ruleNames {
142 0 0   0 0   my $self = shift or confess("%Error: Cannot call rules() without a valid object!");
143 0           return (sort keys %{$self->{_rules}});
  0            
144             }
145              
146             sub examples {
147 0 0   0 0   my $self = shift or confess("%Error: Cannot call without a valid object!");
148 0 0         my $ruleName = shift or confess("%Error: Cannot call without a rule name!");
149 0 0         ($self->rule($ruleName)) or confess("%Error: Cannot find the $ruleName rule on this grammar!");
150 0           my @examples = ( );
151              
152 0 0         if (defined($self->{_examples}{$ruleName})) {
153 0           @examples = @{$self->{_examples}{$ruleName}};
  0            
154             }
155              
156 0           return @examples;
157             }
158              
159             ######################################################################
160             #### Package return
161             1;
162             __END__