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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +28 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +151 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/examples/arithmetic_expression.rb +51 -0
- data/lib/derivation_strategy/base.rb +13 -0
- data/lib/derivation_strategy/leftmost.rb +69 -0
- data/lib/derivation_strategy/random_dampened.rb +115 -0
- data/lib/grammar.rb +31 -0
- data/lib/hash.rb +11 -0
- data/lib/nonterminal.rb +35 -0
- data/lib/panini.rb +6 -0
- data/panini.gemspec +73 -0
- data/spec/derivation_strategy/dampened_probability_production_choice_proxy_spec.rb +194 -0
- data/spec/derivation_strategy/leftmost_spec.rb +90 -0
- data/spec/derivation_strategy/random_dampened_spec.rb +90 -0
- data/spec/grammar_spec.rb +59 -0
- data/spec/nonterminal_spec.rb +79 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/basic_derivation_strategy_shared_example.rb +85 -0
- metadata +146 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe Panini::DerivationStrategy::RandomDampened do
|
5
|
+
it_behaves_like "basic derivation strategy"
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
describe Panini::DerivationStrategy::RandomDampened do
|
10
|
+
|
11
|
+
before (:each) do
|
12
|
+
@g = Panini::Grammar.new.tap do |grammar|
|
13
|
+
grammar.add_nonterminal.add_production([])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises an exception if the damping factor is too small" do
|
18
|
+
lambda { described_class.new(@g, 1.0) }.should raise_error(ArgumentError, "The damping factor must be greater than 0.0 and less than 1.0.")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "raises an exception if the damping factor is too large" do
|
22
|
+
lambda { described_class.new(@g, 0.0) }.should raise_error(ArgumentError, "The damping factor must be greater than 0.0 and less than 1.0.")
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe Panini::DerivationStrategy::RandomDampened, "sentence with an arethmetic expression grammar" do
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
@grammar = Panini::Grammar.new
|
31
|
+
|
32
|
+
expression = @grammar.add_nonterminal
|
33
|
+
term = @grammar.add_nonterminal
|
34
|
+
factor = @grammar.add_nonterminal
|
35
|
+
identifier = @grammar.add_nonterminal
|
36
|
+
number = @grammar.add_nonterminal
|
37
|
+
|
38
|
+
|
39
|
+
# =============
|
40
|
+
# = Terminals =
|
41
|
+
# =============
|
42
|
+
expression.add_production([term, '+', term])
|
43
|
+
expression.add_production([term, '-', term])
|
44
|
+
expression.add_production([term])
|
45
|
+
|
46
|
+
term.add_production([factor, '*', term])
|
47
|
+
term.add_production([factor, '/', term])
|
48
|
+
term.add_production([factor])
|
49
|
+
|
50
|
+
factor.add_production([identifier])
|
51
|
+
factor.add_production([number])
|
52
|
+
factor.add_production(['(', expression, ')'])
|
53
|
+
|
54
|
+
('a'..'z').each do |v|
|
55
|
+
identifier.add_production([v])
|
56
|
+
end
|
57
|
+
|
58
|
+
(0..100).each do |n|
|
59
|
+
number.add_production([n])
|
60
|
+
end
|
61
|
+
|
62
|
+
Kernel::stub(:rand).and_return(0.3)
|
63
|
+
end
|
64
|
+
|
65
|
+
context "with very little damping" do
|
66
|
+
|
67
|
+
before(:each) do
|
68
|
+
@deriver = described_class.new(@grammar, 0.999999999999)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "encounters a stack error" do
|
72
|
+
lambda { @deriver.sentence }.should raise_error(SystemStackError)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
context "with damping" do
|
78
|
+
|
79
|
+
before(:each) do
|
80
|
+
@deriver = described_class.new(@grammar)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns an expected sentence" do
|
84
|
+
@deriver.sentence.should == ["h", "*", "h", "/", "h", "/", "h", "+", "h", "*", "h", "/", "h", "/", "h"]
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
|
4
|
+
describe "Grammar" do
|
5
|
+
|
6
|
+
before (:each) do
|
7
|
+
@g = Panini::Grammar.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "responds to #add_nonterminal" do
|
11
|
+
@g.should respond_to(:add_nonterminal)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "responds to #nonterminals" do
|
15
|
+
@g.should respond_to(:nonterminals)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "responds to #start" do
|
19
|
+
@g.should respond_to(:start)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
describe "Grammar#add_nonterminal" do
|
27
|
+
|
28
|
+
before (:each) do
|
29
|
+
@g = Panini::Grammar.new
|
30
|
+
@n = @g.add_nonterminal()
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns a new Panini::Nonterminal" do
|
34
|
+
@n.should be_an_instance_of(Panini::Nonterminal)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "stores the new Panini::Nonterminal" do
|
38
|
+
@g.nonterminals.should have(1).item
|
39
|
+
@g.nonterminals[0].should == @n
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
describe "Grammar#start" do
|
47
|
+
|
48
|
+
before (:each) do
|
49
|
+
@g = Panini::Grammar.new
|
50
|
+
@nonterminals = (0...3).to_a.map do
|
51
|
+
@g.add_nonterminal
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns the first nonterminal" do
|
56
|
+
@g.start.should == @nonterminals[0]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
|
4
|
+
describe "Nonterminal" do
|
5
|
+
|
6
|
+
before (:each) do
|
7
|
+
@n = Panini::Nonterminal.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "responds to #add_production" do
|
11
|
+
@n.should respond_to(:add_production)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "responds to #productions" do
|
15
|
+
@n.should respond_to(:productions)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe "Nonterminal#add_production with a non-Array arument" do
|
22
|
+
|
23
|
+
before (:each) do
|
24
|
+
@n = Panini::Nonterminal.new
|
25
|
+
end
|
26
|
+
|
27
|
+
it "throws an error" do
|
28
|
+
lambda { @n.add_production('a') }.should raise_error(ArgumentError, "The production must be an Array.")
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
describe "Nonterminal#add_production with a single production" do
|
35
|
+
|
36
|
+
before (:each) do
|
37
|
+
@n = Panini::Nonterminal.new
|
38
|
+
@p = @n.add_production(['a', 'b', 'c'])
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns nil" do
|
42
|
+
@p.should be_nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it "stores the production" do
|
46
|
+
@n.productions.should have(1).item
|
47
|
+
@n.productions[0].should == ['a', 'b', 'c']
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
describe "Nonterminal#add_production with two productions" do
|
55
|
+
|
56
|
+
before (:each) do
|
57
|
+
@n = Panini::Nonterminal.new
|
58
|
+
@p1 = @n.add_production(['a', 'b', 'c'])
|
59
|
+
@p2 = @n.add_production(['x', 'y', 'z'])
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns nil" do
|
63
|
+
@p1.should be_nil
|
64
|
+
@p2.should be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it "stores the productions" do
|
68
|
+
@n.productions.should have(2).items
|
69
|
+
end
|
70
|
+
|
71
|
+
it "stores the first one added first" do
|
72
|
+
@n.productions[0].should == ['a', 'b', 'c']
|
73
|
+
end
|
74
|
+
|
75
|
+
it "stores the second one added last" do
|
76
|
+
@n.productions[1].should == ['x', 'y', 'z']
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'panini'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
# Some basic tests to make sure that a strategy can deal with trivial
|
4
|
+
# grammars. Since these grammars can only create a single sentence, all
|
5
|
+
# strategies should work.
|
6
|
+
|
7
|
+
shared_examples_for "basic derivation strategy" do
|
8
|
+
|
9
|
+
describe "with the production S -> _epsilon_" do
|
10
|
+
|
11
|
+
before (:each) do
|
12
|
+
@g = Panini::Grammar.new
|
13
|
+
@n = @g.add_nonterminal
|
14
|
+
@n.add_production([])
|
15
|
+
end
|
16
|
+
|
17
|
+
it "generates an empty sentence" do
|
18
|
+
d = described_class.new(@g)
|
19
|
+
d.sentence.should be_empty
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
describe "with the production S -> 'a'" do
|
26
|
+
|
27
|
+
before (:each) do
|
28
|
+
@g = Panini::Grammar.new
|
29
|
+
@n = @g.add_nonterminal
|
30
|
+
@n.add_production(['a'])
|
31
|
+
end
|
32
|
+
|
33
|
+
it "generates the sentence ['a']" do
|
34
|
+
d = described_class.new(@g)
|
35
|
+
d.sentence.should == ['a']
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
describe "with the productions S -> A, A -> 'a'" do
|
43
|
+
|
44
|
+
before (:each) do
|
45
|
+
@g = Panini::Grammar.new
|
46
|
+
|
47
|
+
@n_s = @g.add_nonterminal
|
48
|
+
@n_a = @g.add_nonterminal
|
49
|
+
|
50
|
+
@n_s.add_production([@n_a])
|
51
|
+
@n_a.add_production(['a'])
|
52
|
+
end
|
53
|
+
|
54
|
+
it "generates the sentence ['a']" do
|
55
|
+
d = described_class.new(@g)
|
56
|
+
d.sentence.should == ['a']
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
describe "with the productions S -> AB, A -> 'a', B -> 'b'" do
|
64
|
+
|
65
|
+
before (:each) do
|
66
|
+
@g = Panini::Grammar.new
|
67
|
+
|
68
|
+
@n_s = @g.add_nonterminal
|
69
|
+
@n_a = @g.add_nonterminal
|
70
|
+
@n_b = @g.add_nonterminal
|
71
|
+
|
72
|
+
@n_s.add_production([@n_a, @n_b])
|
73
|
+
@n_a.add_production(['a'])
|
74
|
+
@n_b.add_production(['b'])
|
75
|
+
end
|
76
|
+
|
77
|
+
it "generates the sentence ['a', 'b']" do
|
78
|
+
d = described_class.new(@g)
|
79
|
+
d.sentence.should == ['a', 'b']
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: panini
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- mjbellantoni
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-05-16 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 3
|
30
|
+
- 0
|
31
|
+
version: 2.3.0
|
32
|
+
type: :development
|
33
|
+
prerelease: false
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: bundler
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 1
|
44
|
+
- 0
|
45
|
+
- 0
|
46
|
+
version: 1.0.0
|
47
|
+
type: :development
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: jeweler
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 1
|
59
|
+
- 6
|
60
|
+
- 0
|
61
|
+
version: 1.6.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: rcov
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: *id004
|
78
|
+
description: Panini allows you to generate sentences from a context-free grammar, also known as a CFG.
|
79
|
+
email: mjbellantoni@yahoo.com
|
80
|
+
executables: []
|
81
|
+
|
82
|
+
extensions: []
|
83
|
+
|
84
|
+
extra_rdoc_files:
|
85
|
+
- LICENSE.txt
|
86
|
+
- README.rdoc
|
87
|
+
files:
|
88
|
+
- .document
|
89
|
+
- .rspec
|
90
|
+
- Gemfile
|
91
|
+
- Gemfile.lock
|
92
|
+
- LICENSE.txt
|
93
|
+
- README.rdoc
|
94
|
+
- Rakefile
|
95
|
+
- VERSION
|
96
|
+
- examples/arithmetic_expression.rb
|
97
|
+
- lib/derivation_strategy/base.rb
|
98
|
+
- lib/derivation_strategy/leftmost.rb
|
99
|
+
- lib/derivation_strategy/random_dampened.rb
|
100
|
+
- lib/grammar.rb
|
101
|
+
- lib/hash.rb
|
102
|
+
- lib/nonterminal.rb
|
103
|
+
- lib/panini.rb
|
104
|
+
- panini.gemspec
|
105
|
+
- spec/derivation_strategy/dampened_probability_production_choice_proxy_spec.rb
|
106
|
+
- spec/derivation_strategy/leftmost_spec.rb
|
107
|
+
- spec/derivation_strategy/random_dampened_spec.rb
|
108
|
+
- spec/grammar_spec.rb
|
109
|
+
- spec/nonterminal_spec.rb
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
- spec/support/basic_derivation_strategy_shared_example.rb
|
112
|
+
has_rdoc: true
|
113
|
+
homepage: http://github.com/mjbellantoni/panini
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
hash: 286269899475831067
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
version: "0"
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
segments:
|
136
|
+
- 0
|
137
|
+
version: "0"
|
138
|
+
requirements: []
|
139
|
+
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 1.3.7
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: Create sentences from a context-free grammar (CFG)
|
145
|
+
test_files: []
|
146
|
+
|