panini 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,13 +1,8 @@
1
1
  source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
5
2
 
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
8
3
  group :development do
9
4
  gem "rspec", "~> 2.3.0"
10
- gem "bundler", "~> 1.0.0"
5
+ gem "bundler", "~> 1.0"
11
6
  gem "jeweler", "~> 1.6.0"
12
7
  gem "rcov", ">= 0"
13
8
  end
@@ -1,14 +1,14 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- diff-lcs (1.1.2)
4
+ diff-lcs (1.1.3)
5
5
  git (1.2.5)
6
- jeweler (1.6.0)
7
- bundler (~> 1.0.0)
6
+ jeweler (1.6.4)
7
+ bundler (~> 1.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
- rake (0.8.7)
11
- rcov (0.9.9)
10
+ rake (0.9.2)
11
+ rcov (0.9.10)
12
12
  rspec (2.3.0)
13
13
  rspec-core (~> 2.3.0)
14
14
  rspec-expectations (~> 2.3.0)
@@ -22,7 +22,7 @@ PLATFORMS
22
22
  ruby
23
23
 
24
24
  DEPENDENCIES
25
- bundler (~> 1.0.0)
25
+ bundler (~> 1.0)
26
26
  jeweler (~> 1.6.0)
27
27
  rcov
28
28
  rspec (~> 2.3.0)
@@ -57,11 +57,24 @@ Here's how the grammar from above is defined:
57
57
  === Derivators
58
58
 
59
59
  Derivators are objects that take a Panini::Grammar and then apply the rules to generate a sentence. Creating the sentences
60
- from the grammar can be tricky, and certain derivation strategies may be better for some grammars.
61
- Currently, the main derivator is the Panini::DerivationStrategy::RandomDampened derivator.
60
+ from the grammar can be tricky, and certain derivation strategies may be better for some grammars. There are currently two main derivators.
61
+
62
+ ==== Panini::DerivationStrategy::RandomDampened
63
+
64
+ This strategy creates random sentences given a grammar. It employs a dampening factor to keep the computation of the sentence from blowing up.
65
+
66
+ derivator = Panini::DerivationStrategy::RandomDampened.new(grammar)
67
+
68
+ This will return a different sentence each time it is called. It may (and probably will) return the same sentence multiple times.
69
+
70
+ ==== Panini::DerivationStrategy::Exhaustive
71
+
72
+ This strategy is used to exhaustively create all of the sentences that may be created by a grammar.
62
73
 
63
74
  derivator = Panini::DerivationStrategy::RandomDampened.new(grammar)
64
75
 
76
+ This will return a new sentence with each call. If there are no additional sentences to be created it will return nil. The same sentence may be returned multiple times if the grammar can derive the sentence in multiple ways.
77
+
65
78
  === Generating a Sentence
66
79
 
67
80
  To generate a sentence, call the derivator's sentence method like thus:
@@ -119,6 +132,9 @@ In this example, we create a grammar that generates mathematical expressions.
119
132
  end
120
133
 
121
134
  == Contributing to panini
135
+
136
+ Contributions to this gem are appreciated!
137
+
122
138
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
123
139
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
124
140
  * Fork the project
@@ -133,9 +149,10 @@ In this example, we create a grammar that generates mathematical expressions.
133
149
  * Detect invalid grammars
134
150
  * Weighted productions.
135
151
  * Arbitrary start symbol.
136
- * Support Enumerator?
137
- * DSL?
152
+ * Support Enumerator!
153
+ * DSL or string based grammar definitions
138
154
  * Purdom Derivator?
155
+ * Actions
139
156
 
140
157
  === Examples
141
158
  * Natural language
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.1.0
@@ -0,0 +1,82 @@
1
+ class Array
2
+
3
+ def top
4
+ self.last
5
+ end
6
+
7
+ def has_nonterminals?
8
+ self.any? do |term|
9
+ term.class == Panini::Nonterminal
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+
16
+ module Panini
17
+ module DerivationStrategy
18
+
19
+ class Exhaustive < Base
20
+
21
+ def initialize(grammar)
22
+ super(grammar)
23
+ @in_progress_work = [].push([@grammar.start])
24
+ end
25
+
26
+ # Generates a sentence.
27
+ def sentence
28
+ unless @in_progress_work.empty?
29
+ while @in_progress_work.top.has_nonterminals?
30
+ generate_work(@in_progress_work.pop)
31
+ end
32
+ @in_progress_work.pop
33
+ end
34
+ end
35
+
36
+ def generate_work(derived_sentence)
37
+
38
+ # Find the leftmost nonterminal.
39
+ i = derived_sentence.index do |term|
40
+ term.class == Nonterminal
41
+ end
42
+ nonterminal = derived_sentence[i]
43
+
44
+ # Substitute in each production for the nonterminal. Do it
45
+ # in reverse because it causes the results to happen in a more
46
+ # intuitive order.
47
+ nonterminal.productions.reverse.each do |production|
48
+ j = 0
49
+ newly_derived_sentence = derived_sentence.flat_map do |term|
50
+ if (i == j)
51
+ j += 1
52
+ production
53
+ else
54
+ j += 1
55
+ term
56
+ end
57
+ end
58
+ @in_progress_work.push(newly_derived_sentence)
59
+ end
60
+
61
+ end
62
+ private :generate_work
63
+
64
+ #
65
+ # def substitution_pass(derived_sentence)
66
+ # substituted = false
67
+ # derived_sentence = derived_sentence.flat_map do |term|
68
+ # if !substituted && (term.class == Nonterminal)
69
+ # substituted = true
70
+ # @production_proxies[term].production
71
+ # else
72
+ # term
73
+ # end
74
+ # end
75
+ # return derived_sentence, substituted
76
+ # end
77
+ # private :substitution_pass
78
+
79
+ end
80
+
81
+ end
82
+ end
@@ -3,4 +3,5 @@ require "hash"
3
3
  require "nonterminal"
4
4
  require "derivation_strategy/base"
5
5
  require "derivation_strategy/leftmost"
6
+ require "derivation_strategy/exhaustive"
6
7
  require "derivation_strategy/random_dampened"
@@ -4,14 +4,14 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = %q{panini}
8
- s.version = "1.0.0"
7
+ s.name = "panini"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
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}
12
+ s.date = "2011-09-13"
13
+ s.description = "Panini allows you to generate sentences from a context-free grammar, also known as a CFG."
14
+ s.email = "mjbellantoni@yahoo.com"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
17
  "README.rdoc"
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
27
27
  "VERSION",
28
28
  "examples/arithmetic_expression.rb",
29
29
  "lib/derivation_strategy/base.rb",
30
+ "lib/derivation_strategy/exhaustive.rb",
30
31
  "lib/derivation_strategy/leftmost.rb",
31
32
  "lib/derivation_strategy/random_dampened.rb",
32
33
  "lib/grammar.rb",
@@ -35,6 +36,7 @@ Gem::Specification.new do |s|
35
36
  "lib/panini.rb",
36
37
  "panini.gemspec",
37
38
  "spec/derivation_strategy/dampened_probability_production_choice_proxy_spec.rb",
39
+ "spec/derivation_strategy/exhaustive_spec.rb",
38
40
  "spec/derivation_strategy/leftmost_spec.rb",
39
41
  "spec/derivation_strategy/random_dampened_spec.rb",
40
42
  "spec/grammar_spec.rb",
@@ -42,30 +44,29 @@ Gem::Specification.new do |s|
42
44
  "spec/spec_helper.rb",
43
45
  "spec/support/basic_derivation_strategy_shared_example.rb"
44
46
  ]
45
- s.homepage = %q{http://github.com/mjbellantoni/panini}
47
+ s.homepage = "http://github.com/mjbellantoni/panini"
46
48
  s.licenses = ["MIT"]
47
49
  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
+ s.rubygems_version = "1.8.10"
51
+ s.summary = "Create sentences from a context-free grammar (CFG)"
50
52
 
51
53
  if s.respond_to? :specification_version then
52
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
54
  s.specification_version = 3
54
55
 
55
56
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
57
  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<bundler>, ["~> 1.0"])
58
59
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
59
60
  s.add_development_dependency(%q<rcov>, [">= 0"])
60
61
  else
61
62
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
62
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
63
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
63
64
  s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
64
65
  s.add_dependency(%q<rcov>, [">= 0"])
65
66
  end
66
67
  else
67
68
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
68
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
69
70
  s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
70
71
  s.add_dependency(%q<rcov>, [">= 0"])
71
72
  end
@@ -0,0 +1,119 @@
1
+ require "spec_helper"
2
+
3
+
4
+ describe Panini::DerivationStrategy::Exhaustive do
5
+ it_behaves_like "basic derivation strategy"
6
+ end
7
+
8
+
9
+ describe "Grammar with the production S -> AAB, A -> 'a' | 'x', B -> 'b'" do
10
+
11
+ before (:each) do
12
+ @g = Panini::Grammar.new
13
+
14
+ @n_s = @g.add_nonterminal
15
+ @n_a = @g.add_nonterminal
16
+ @n_b = @g.add_nonterminal
17
+
18
+ @n_s.add_production([@n_a, @n_a, @n_b])
19
+ @n_a.add_production(['a'])
20
+ @n_a.add_production(['x'])
21
+ @n_b.add_production(['b'])
22
+ end
23
+
24
+ it "generates the sentence ['a', 'a', 'b'] first" do
25
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
26
+ d.sentence.should == ['a', 'a', 'b']
27
+ end
28
+
29
+ it "generates the sentence ['a', 'x', 'b'] next" do
30
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
31
+ d.sentence
32
+ d.sentence.should == ['a', 'x', 'b']
33
+ end
34
+
35
+ it "generates the sentence ['x', 'a', 'b'] next" do
36
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
37
+ d.sentence
38
+ d.sentence
39
+ d.sentence.should == ['x', 'a', 'b']
40
+ end
41
+
42
+ it "generates the sentence ['x', 'x', 'b'] next" do
43
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
44
+ d.sentence
45
+ d.sentence
46
+ d.sentence
47
+ d.sentence.should == ['x', 'x', 'b']
48
+ end
49
+
50
+ it "generates nil next" do
51
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
52
+ d.sentence
53
+ d.sentence
54
+ d.sentence
55
+ d.sentence
56
+ d.sentence.should be_nil
57
+ end
58
+
59
+ end
60
+
61
+
62
+ describe "Grammar with the production S -> 'a' | 'b'" do
63
+
64
+ before (:each) do
65
+ @g = Panini::Grammar.new
66
+ @n = @g.add_nonterminal
67
+ @n.add_production(['a'])
68
+ @n.add_production(['b'])
69
+ end
70
+
71
+ it "generates the sentence ['a']" do
72
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
73
+ d.sentence.should == ['a']
74
+ end
75
+
76
+ it "generates the sentence ['b']" do
77
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
78
+ d.sentence
79
+ d.sentence.should == ['b']
80
+ end
81
+
82
+ end
83
+
84
+
85
+ describe "Grammar with the production S -> xAyBz, A -> 'a' | 'aa', B -> 'b' | 'bb' " do
86
+
87
+ before (:each) do
88
+ @g = Panini::Grammar.new
89
+
90
+ @n_s = @g.add_nonterminal
91
+ @n_a = @g.add_nonterminal
92
+ @n_b = @g.add_nonterminal
93
+
94
+ @n_s.add_production(['x', @n_a, 'y', @n_b, 'z'])
95
+ @n_a.add_production(['a'])
96
+ @n_a.add_production(['aa'])
97
+ @n_b.add_production(['b'])
98
+ @n_b.add_production(['bb'])
99
+ end
100
+
101
+ it "generates the sentence ['x', 'a', 'y', 'b', 'z'] first" do
102
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
103
+ d.sentence.should == ['x', 'a', 'y', 'b', 'z']
104
+ end
105
+
106
+ it "generates the sentence ['x', 'a', 'y', 'bb', 'z'] next" do
107
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
108
+ d.sentence.should
109
+ d.sentence.should == ['x', 'a', 'y', 'bb', 'z']
110
+ end
111
+
112
+ it "generates the sentence ['x', 'aa', 'y', 'b', 'z'] next" do
113
+ d = Panini::DerivationStrategy::Exhaustive.new(@g)
114
+ d.sentence.should
115
+ d.sentence.should
116
+ d.sentence.should == ['x', 'aa', 'y', 'b', 'z']
117
+ end
118
+
119
+ end
@@ -71,20 +71,3 @@ describe "Grammar with the production S -> S | 'a' | 'b'" do
71
71
  end
72
72
 
73
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
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panini
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 1
7
- - 0
8
- - 0
9
- version: 1.0.0
4
+ prerelease:
5
+ version: 1.1.0
10
6
  platform: ruby
11
7
  authors:
12
8
  - mjbellantoni
@@ -14,8 +10,7 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2011-05-16 00:00:00 -04:00
18
- default_executable:
13
+ date: 2011-09-13 00:00:00 Z
19
14
  dependencies:
20
15
  - !ruby/object:Gem::Dependency
21
16
  name: rspec
@@ -24,10 +19,6 @@ dependencies:
24
19
  requirements:
25
20
  - - ~>
26
21
  - !ruby/object:Gem::Version
27
- segments:
28
- - 2
29
- - 3
30
- - 0
31
22
  version: 2.3.0
32
23
  type: :development
33
24
  prerelease: false
@@ -39,11 +30,7 @@ dependencies:
39
30
  requirements:
40
31
  - - ~>
41
32
  - !ruby/object:Gem::Version
42
- segments:
43
- - 1
44
- - 0
45
- - 0
46
- version: 1.0.0
33
+ version: "1.0"
47
34
  type: :development
48
35
  prerelease: false
49
36
  version_requirements: *id002
@@ -54,10 +41,6 @@ dependencies:
54
41
  requirements:
55
42
  - - ~>
56
43
  - !ruby/object:Gem::Version
57
- segments:
58
- - 1
59
- - 6
60
- - 0
61
44
  version: 1.6.0
62
45
  type: :development
63
46
  prerelease: false
@@ -69,8 +52,6 @@ dependencies:
69
52
  requirements:
70
53
  - - ">="
71
54
  - !ruby/object:Gem::Version
72
- segments:
73
- - 0
74
55
  version: "0"
75
56
  type: :development
76
57
  prerelease: false
@@ -95,6 +76,7 @@ files:
95
76
  - VERSION
96
77
  - examples/arithmetic_expression.rb
97
78
  - lib/derivation_strategy/base.rb
79
+ - lib/derivation_strategy/exhaustive.rb
98
80
  - lib/derivation_strategy/leftmost.rb
99
81
  - lib/derivation_strategy/random_dampened.rb
100
82
  - lib/grammar.rb
@@ -103,13 +85,13 @@ files:
103
85
  - lib/panini.rb
104
86
  - panini.gemspec
105
87
  - spec/derivation_strategy/dampened_probability_production_choice_proxy_spec.rb
88
+ - spec/derivation_strategy/exhaustive_spec.rb
106
89
  - spec/derivation_strategy/leftmost_spec.rb
107
90
  - spec/derivation_strategy/random_dampened_spec.rb
108
91
  - spec/grammar_spec.rb
109
92
  - spec/nonterminal_spec.rb
110
93
  - spec/spec_helper.rb
111
94
  - spec/support/basic_derivation_strategy_shared_example.rb
112
- has_rdoc: true
113
95
  homepage: http://github.com/mjbellantoni/panini
114
96
  licenses:
115
97
  - MIT
@@ -123,7 +105,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
105
  requirements:
124
106
  - - ">="
125
107
  - !ruby/object:Gem::Version
126
- hash: 286269899475831067
108
+ hash: -1665720431960213425
127
109
  segments:
128
110
  - 0
129
111
  version: "0"
@@ -132,13 +114,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
114
  requirements:
133
115
  - - ">="
134
116
  - !ruby/object:Gem::Version
135
- segments:
136
- - 0
137
117
  version: "0"
138
118
  requirements: []
139
119
 
140
120
  rubyforge_project:
141
- rubygems_version: 1.3.7
121
+ rubygems_version: 1.8.10
142
122
  signing_key:
143
123
  specification_version: 3
144
124
  summary: Create sentences from a context-free grammar (CFG)