panini 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ module Panini
2
+
3
+
4
+ # The Grammar stores the start symbol and nonterminals.
5
+ class Grammar
6
+
7
+ def initialize
8
+ @nonterminals = []
9
+ end
10
+
11
+ # Returns the grammar's start symbol. This will always be the first
12
+ # nonterminal added to the grammar.
13
+ def start
14
+ @nonterminals[0]
15
+ end
16
+
17
+ # Add a nonterminal to the grammar.
18
+ def add_nonterminal(name = nil)
19
+ Panini::Nonterminal.new(name).tap do |new_nonterminal|
20
+ @nonterminals << new_nonterminal
21
+ end
22
+ end
23
+
24
+ # The list of nonterminals in the grammar.
25
+ def nonterminals
26
+ @nonterminals.dup
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,11 @@
1
+ class Hash
2
+
3
+ def map(&block)
4
+ mapped_hash = {}
5
+ self.each do |key, value|
6
+ mapped_hash[key] = yield value
7
+ end
8
+ mapped_hash
9
+ end
10
+
11
+ end
@@ -0,0 +1,35 @@
1
+ module Panini
2
+
3
+ class Nonterminal
4
+
5
+ attr_reader :name
6
+
7
+ # Initialize a nonterminal. Optionally specify a name.
8
+ def initialize(name=nil)
9
+ @productions = []
10
+ @name = name
11
+ end
12
+
13
+ # Add a production to the nonterminal. It must be an array, but the array can
14
+ # contain any type of Ruby object.
15
+ #
16
+ # nonterminal.add_production([1, 'a', lambda { ...} ])
17
+ #
18
+ def add_production(production)
19
+ raise ArgumentError, "The production must be an Array." unless production.class == Array
20
+ @productions << production.dup
21
+ nil
22
+ end
23
+
24
+ # The productions for the nonterminal.
25
+ def productions
26
+ @productions.dup
27
+ end
28
+
29
+ def to_s
30
+ name.nil? ? super : @name
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,6 @@
1
+ require "grammar"
2
+ require "hash"
3
+ require "nonterminal"
4
+ require "derivation_strategy/base"
5
+ require "derivation_strategy/leftmost"
6
+ require "derivation_strategy/random_dampened"
@@ -0,0 +1,73 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{panini}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["mjbellantoni"]
12
+ s.date = %q{2011-05-16}
13
+ s.description = %q{Panini allows you to generate sentences from a context-free grammar, also known as a CFG.}
14
+ s.email = %q{mjbellantoni@yahoo.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "examples/arithmetic_expression.rb",
29
+ "lib/derivation_strategy/base.rb",
30
+ "lib/derivation_strategy/leftmost.rb",
31
+ "lib/derivation_strategy/random_dampened.rb",
32
+ "lib/grammar.rb",
33
+ "lib/hash.rb",
34
+ "lib/nonterminal.rb",
35
+ "lib/panini.rb",
36
+ "panini.gemspec",
37
+ "spec/derivation_strategy/dampened_probability_production_choice_proxy_spec.rb",
38
+ "spec/derivation_strategy/leftmost_spec.rb",
39
+ "spec/derivation_strategy/random_dampened_spec.rb",
40
+ "spec/grammar_spec.rb",
41
+ "spec/nonterminal_spec.rb",
42
+ "spec/spec_helper.rb",
43
+ "spec/support/basic_derivation_strategy_shared_example.rb"
44
+ ]
45
+ s.homepage = %q{http://github.com/mjbellantoni/panini}
46
+ s.licenses = ["MIT"]
47
+ s.require_paths = ["lib"]
48
+ s.rubygems_version = %q{1.3.7}
49
+ s.summary = %q{Create sentences from a context-free grammar (CFG)}
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
57
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
58
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
59
+ s.add_development_dependency(%q<rcov>, [">= 0"])
60
+ else
61
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
62
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
63
+ s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
64
+ s.add_dependency(%q<rcov>, [">= 0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ end
72
+ end
73
+
@@ -0,0 +1,194 @@
1
+ require "spec_helper"
2
+
3
+
4
+ describe Panini::DerivationStrategy::DampenedProbabilityProductionChoiceProxy do
5
+
6
+ it "responds to #production" do
7
+ described_class.new(Panini::Nonterminal.new).should respond_to(:production)
8
+ end
9
+
10
+ end
11
+
12
+
13
+ describe Panini::DerivationStrategy::DampenedProbabilityProductionChoiceProxy, "#production" do
14
+
15
+ context "with damping 0.50" do
16
+
17
+ before(:each) do
18
+ @damping = 0.50
19
+ end
20
+
21
+ context "with a production N -> 'a' and rand() -> 0.25" do
22
+
23
+ before(:each) do
24
+ n = Panini::Nonterminal.new
25
+ n.add_production(['a'])
26
+ @proxy = described_class.new(n, @damping)
27
+ Kernel::stub(:rand).and_return(0.25)
28
+ end
29
+
30
+ it "returns ['a'] after one call" do
31
+ @proxy.production.should == ['a']
32
+ end
33
+
34
+ it "returns ['a'] after two calls" do
35
+ @proxy.production
36
+ @proxy.production.should == ['a']
37
+ end
38
+
39
+ it "returns ['a'] after three calls" do
40
+ @proxy.production
41
+ @proxy.production
42
+ @proxy.production.should == ['a']
43
+ end
44
+
45
+ end
46
+
47
+ context "with a production N -> 'a' | 'b' and rand() -> 0.25" do
48
+
49
+ before(:each) do
50
+ n = Panini::Nonterminal.new
51
+ n.add_production(['a'])
52
+ n.add_production(['b'])
53
+ @proxy = described_class.new(n, @damping)
54
+ Kernel::stub(:rand).and_return(0.25)
55
+ end
56
+
57
+ it "returns ['a'] after one call" do
58
+ @proxy.production.should == ['a']
59
+ end
60
+
61
+ it "returns ['a'] after two calls" do
62
+ @proxy.production
63
+ @proxy.production.should == ['a']
64
+ end
65
+
66
+ it "returns ['b'] after three calls" do
67
+ @proxy.production
68
+ @proxy.production
69
+ @proxy.production.should == ['b']
70
+ end
71
+
72
+ end
73
+
74
+ context "with a production N -> 'a' | 'b' | 'c' and rand() -> 0.3" do
75
+
76
+ before(:each) do
77
+ n = Panini::Nonterminal.new
78
+ n.add_production(['a'])
79
+ n.add_production(['b'])
80
+ n.add_production(['c'])
81
+ @proxy = described_class.new(n, @damping)
82
+ Kernel::stub(:rand).and_return(0.3)
83
+ end
84
+
85
+ it "returns ['a'] after one call" do
86
+ @proxy.production.should == ['a']
87
+ end
88
+
89
+ it "returns ['b'] after two calls" do
90
+ @proxy.production
91
+ @proxy.production.should == ['b']
92
+ end
93
+
94
+ it "returns ['b'] after three calls" do
95
+ @proxy.production
96
+ @proxy.production
97
+ @proxy.production.should == ['b']
98
+ end
99
+
100
+ it "returns ['b'] after four calls" do
101
+ @proxy.production
102
+ @proxy.production
103
+ @proxy.production
104
+ @proxy.production.should == ['b']
105
+ end
106
+
107
+ it "returns ['a'] after five calls" do
108
+ @proxy.production
109
+ @proxy.production
110
+ @proxy.production
111
+ @proxy.production
112
+ @proxy.production.should == ['a']
113
+ end
114
+
115
+ it "returns ['c'] after six calls" do
116
+ @proxy.production
117
+ @proxy.production
118
+ @proxy.production
119
+ @proxy.production
120
+ @proxy.production
121
+ @proxy.production.should == ['c']
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+
128
+ end
129
+
130
+
131
+
132
+ describe Panini::DerivationStrategy::DampenedProbabilityProductionChoiceProxy, "#clone" do
133
+
134
+ context "with damping 0.50, a production N -> 'a' | 'b' | 'c' and rand() -> 0.3" do
135
+
136
+ before(:each) do
137
+ n = Panini::Nonterminal.new
138
+ n.add_production(['a'])
139
+ n.add_production(['b'])
140
+ n.add_production(['c'])
141
+ @proxy = described_class.new(n, 0.50)
142
+ Kernel::stub(:rand).and_return(0.3)
143
+ end
144
+
145
+ context "and a clone" do
146
+
147
+ before(:each) do
148
+ @clone_proxy = @proxy.clone
149
+ @clone_proxy.stub(:rand).and_return(0.3)
150
+ end
151
+
152
+ context "the original" do
153
+
154
+ it "returns ['a'] after one call" do
155
+ @proxy.production.should == ['a']
156
+ end
157
+
158
+ it "returns ['b'] after two calls" do
159
+ @proxy.production
160
+ @proxy.production.should == ['b']
161
+ end
162
+
163
+ it "returns ['b'] after three calls" do
164
+ @proxy.production
165
+ @proxy.production
166
+ @proxy.production.should == ['b']
167
+ end
168
+
169
+ end
170
+
171
+ context "the clone" do
172
+
173
+ it "returns ['a'] after one call" do
174
+ @clone_proxy.production.should == ['a']
175
+ end
176
+
177
+ it "returns ['b'] after two calls" do
178
+ @clone_proxy.production
179
+ @clone_proxy.production.should == ['b']
180
+ end
181
+
182
+ it "returns ['b'] after three calls" do
183
+ @clone_proxy.production
184
+ @clone_proxy.production
185
+ @clone_proxy.production.should == ['b']
186
+ end
187
+
188
+ end
189
+
190
+ end
191
+
192
+ end
193
+
194
+ end
@@ -0,0 +1,90 @@
1
+ require "spec_helper"
2
+
3
+
4
+ describe Panini::DerivationStrategy::Leftmost do
5
+ it_behaves_like "basic derivation strategy"
6
+ end
7
+
8
+
9
+
10
+ describe "Grammar with the production S -> AAB, A -> 'a' | 'x', B -> 'b'" do
11
+
12
+ before (:each) do
13
+ @g = Panini::Grammar.new
14
+
15
+ @n_s = @g.add_nonterminal
16
+ @n_a = @g.add_nonterminal
17
+ @n_b = @g.add_nonterminal
18
+
19
+ @n_s.add_production([@n_a, @n_a, @n_b])
20
+ @n_a.add_production(['a'])
21
+ @n_a.add_production(['x'])
22
+ @n_b.add_production(['b'])
23
+ end
24
+
25
+ it "generates the sentence ['a', 'x', 'b']" do
26
+ d = Panini::DerivationStrategy::Leftmost.new(@g)
27
+ d.sentence.should == ['a', 'x', 'b']
28
+ end
29
+
30
+ end
31
+
32
+
33
+
34
+ describe "Grammar with the production S -> 'a' | 'b'" do
35
+
36
+ before (:each) do
37
+ @g = Panini::Grammar.new
38
+ @n = @g.add_nonterminal
39
+ @n.add_production(['a'])
40
+ @n.add_production(['b'])
41
+ end
42
+
43
+ it "generates the sentence ['a']" do
44
+ d = Panini::DerivationStrategy::Leftmost.new(@g)
45
+ d.sentence.should == ['a']
46
+ end
47
+
48
+ end
49
+
50
+
51
+
52
+ describe "Grammar with the production S -> S | 'a' | 'b'" do
53
+
54
+ before (:each) do
55
+ @g = Panini::Grammar.new
56
+ @n = @g.add_nonterminal
57
+ @n.add_production([@n])
58
+ @n.add_production(['a'])
59
+ @n.add_production(['b'])
60
+
61
+ @deriver = Panini::DerivationStrategy::Leftmost.new(@g)
62
+ end
63
+
64
+ it "generates the sentence ['a'] first" do
65
+ @deriver.sentence.should == ['a']
66
+ end
67
+
68
+ it "generates the sentence ['b'] second" do
69
+ @deriver.sentence.should
70
+ @deriver.sentence.should == ['b']
71
+ end
72
+
73
+ end
74
+
75
+
76
+ describe "with the production S -> 'a' | 'b'" do
77
+
78
+ before (:each) do
79
+ @g = Panini::Grammar.new
80
+ @n = @g.add_nonterminal
81
+ @n.add_production(['a'])
82
+ @n.add_production(['b'])
83
+ end
84
+
85
+ it "generates the sentence ['a']" do
86
+ d = Panini::DerivationStrategy::Leftmost.new(@g)
87
+ d.sentence.should == ['a']
88
+ end
89
+
90
+ end