rley 0.3.01 → 0.3.04

Sign up to get free protection for your applications and to get access to all the features.
@@ -63,7 +63,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
63
63
  parser = Parser::GFGEarleyParser.new(sample_grammar)
64
64
  parser.parse(sample_tokens)
65
65
  end
66
-
66
+
67
67
  let(:accept_entry) { sample_result.accepting_entry }
68
68
  let(:accept_index) { sample_result.chart.last_index }
69
69
  subject { ParseWalkerFactory.new }
@@ -100,7 +100,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
100
100
  event3 = walker.next
101
101
  expectations = [:visit, 'S. | 0', 4]
102
102
  event_expectations(event3, expectations)
103
-
103
+
104
104
  # Backtrack created: first alternative selected
105
105
  event4 = walker.next
106
106
  expectations = [:visit, 'S => a T . | 0', 4]
@@ -112,16 +112,16 @@ module Rley # Open this namespace to avoid module qualifier prefixes
112
112
 
113
113
  event6 = walker.next
114
114
  expectations = [:visit, 'T => b b b . | 1', 4]
115
- event_expectations(event6, expectations)
116
-
115
+ event_expectations(event6, expectations)
116
+
117
117
  event7 = walker.next
118
118
  expectations = [:visit, 'T => b b . b | 1', 3]
119
- event_expectations(event7, expectations)
119
+ event_expectations(event7, expectations)
120
120
 
121
121
  event8 = walker.next
122
122
  expectations = [:visit, 'T => b . b b | 1', 2]
123
- event_expectations(event8, expectations)
124
-
123
+ event_expectations(event8, expectations)
124
+
125
125
  event9 = walker.next
126
126
  expectations = [:visit, 'T => . b b b | 1', 1]
127
127
  event_expectations(event9, expectations)
@@ -144,7 +144,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
144
144
 
145
145
  event14 = walker.next
146
146
  expectations = [:visit, 'Phi => . S | 0', 0]
147
- event_expectations(event14, expectations)
147
+ event_expectations(event14, expectations)
148
148
 
149
149
  event15 = walker.next
150
150
  expectations = [:visit, '.Phi | 0', 0]
@@ -153,80 +153,100 @@ module Rley # Open this namespace to avoid module qualifier prefixes
153
153
  # Backtracking is occurring
154
154
  event16 = walker.next
155
155
  expectations = [:backtrack, 'S. | 0', 4]
156
- event_expectations(event16, expectations)
157
-
158
- event18 = walker.next
156
+ event_expectations(event16, expectations)
157
+
158
+ event17 = walker.next
159
159
  expectations = [:visit, 'S => A T . | 0', 4]
160
+ event_expectations(event17, expectations)
161
+
162
+ event18 = walker.next
163
+ expectations = [:revisit, 'T. | 1', 4]
160
164
  event_expectations(event18, expectations)
161
165
 
166
+ # Multiple visit occurred: jump to antecedent of start entry
162
167
  event19 = walker.next
163
- expectations = [:revisit, 'T. | 1', 4]
168
+ expectations = [:visit, 'S => A . T | 0', 1]
164
169
  event_expectations(event19, expectations)
165
170
 
166
- # Multiple visit occurred: jump to antecedent of start entry
167
171
  event20 = walker.next
168
- expectations = [:visit, 'S => A . T | 0', 1]
172
+ expectations = [:visit, 'A. | 0', 1]
169
173
  event_expectations(event20, expectations)
170
174
 
175
+ # Backtrack created: first alternative selected
171
176
  event21 = walker.next
172
- expectations = [:visit, 'A. | 0', 1]
177
+ expectations = [:visit, 'A => a . | 0', 1]
173
178
  event_expectations(event21, expectations)
174
-
175
- # Backtrack created: first alternative selected
179
+
176
180
  event22 = walker.next
177
- expectations = [:visit, 'A => a . | 0', 1]
178
- event_expectations(event22, expectations)
179
-
180
- event23 = walker.next
181
181
  expectations = [:visit, 'A => . a | 0', 0]
182
+ event_expectations(event22, expectations)
183
+
184
+ event23 = walker.next
185
+ expectations = [:visit, '.A | 0', 0]
182
186
  event_expectations(event23, expectations)
183
187
 
184
188
  event24 = walker.next
185
- expectations = [:visit, '.A | 0', 0]
189
+ expectations = [:visit, 'S => . A T | 0', 0]
186
190
  event_expectations(event24, expectations)
187
191
 
188
192
  event25 = walker.next
189
- expectations = [:visit, 'S => . A T | 0', 0]
193
+ expectations = [:revisit, '.S | 0', 0]
190
194
  event_expectations(event25, expectations)
191
195
 
192
- # Backtracking is occurring
193
196
  event26 = walker.next
194
- expectations = [:backtrack, 'A. | 0', 1]
195
- event_expectations(event26, expectations)
196
-
197
+ expectations = [:revisit, '.Phi | 0', 0]
198
+ event_expectations(event26, expectations)
199
+
200
+ # Backtracking is occurring
197
201
  event27 = walker.next
198
- expectations = [:visit, 'A => B A . | 0', 1]
202
+ expectations = [:backtrack, 'A. | 0', 1]
199
203
  event_expectations(event27, expectations)
200
-
204
+
201
205
  event28 = walker.next
202
- expectations = [:revisit, 'A. | 0', 1]
206
+ expectations = [:visit, 'A => B A . | 0', 1]
203
207
  event_expectations(event28, expectations)
204
208
 
205
209
  event29 = walker.next
206
- expectations = [:visit, 'A => B . A | 0', 0]
207
- event_expectations(event29, expectations)
210
+ expectations = [:revisit, 'A. | 0', 1]
211
+ event_expectations(event29, expectations)
208
212
 
209
213
  event30 = walker.next
210
- expectations = [:visit, 'B. | 0', 0]
214
+ expectations = [:visit, 'A => B . A | 0', 0]
211
215
  event_expectations(event30, expectations)
212
216
 
213
217
  event31 = walker.next
214
- expectations = [:visit, 'B => . | 0', 0]
218
+ expectations = [:visit, 'B. | 0', 0]
215
219
  event_expectations(event31, expectations)
216
220
 
217
221
  event32 = walker.next
218
- expectations = [:visit, '.B | 0', 0]
219
- event_expectations(event32, expectations)
222
+ expectations = [:visit, 'B => . | 0', 0]
223
+ event_expectations(event32, expectations)
220
224
 
221
225
  event33 = walker.next
226
+ expectations = [:visit, '.B | 0', 0]
227
+ event_expectations(event33, expectations)
228
+
229
+ event34 = walker.next
222
230
  expectations = [:visit, 'A => . B A | 0', 0]
223
- event_expectations(event33, expectations)
231
+ event_expectations(event34, expectations)
232
+
233
+ event35 = walker.next
234
+ expectations = [:revisit, '.A | 0', 0]
235
+ event_expectations(event35, expectations)
236
+
237
+ event36 = walker.next
238
+ expectations = [:revisit, '.S | 0', 0]
239
+ event_expectations(event36, expectations)
240
+
241
+ event37 = walker.next
242
+ expectations = [:revisit, '.Phi | 0', 0]
243
+ event_expectations(event37, expectations)
224
244
  end
225
-
245
+
226
246
  it 'should raise an exception at end of visit' do
227
247
  walker = subject.build_walker(accept_entry, accept_index)
228
- 32.times { walker.next }
229
-
248
+ 37.times { walker.next }
249
+
230
250
  expect{ walker.next }.to raise_error(StopIteration)
231
251
  end
232
252
 
@@ -54,8 +54,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
54
54
  # Adding states
55
55
  subject.push_state(state1)
56
56
  subject.push_state(state2)
57
- allow(dotted_rule1).to receive(:production).and_return(:dummy)
58
- allow(dotted_rule2).to receive(:production).and_return(a_prod)
57
+ expect(dotted_rule1).to receive(:production).and_return(:dummy)
58
+ expect(dotted_rule2).to receive(:production).and_return(a_prod)
59
59
  expect(subject.states_for(a_prod)).to eq([state2])
60
60
  end
61
61
 
@@ -67,11 +67,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
67
67
  # Adding states
68
68
  subject.push_state(state1)
69
69
  subject.push_state(state2)
70
- allow(dotted_rule1).to receive(:production).and_return(prod1)
71
- allow(prod1).to receive(:lhs).and_return(:dummy)
72
- allow(dotted_rule2).to receive(:production).and_return(prod2)
73
- allow(dotted_rule2).to receive(:reduce_item?).and_return(true)
74
- allow(prod2).to receive(:lhs).and_return(non_term)
70
+ expect(dotted_rule1).to receive(:production).and_return(prod1)
71
+ expect(prod1).to receive(:lhs).and_return(:dummy)
72
+ expect(dotted_rule2).to receive(:production).and_return(prod2)
73
+ expect(dotted_rule2).to receive(:reduce_item?).and_return(true)
74
+ expect(prod2).to receive(:lhs).and_return(non_term)
75
75
  expect(subject.states_rewriting(non_term)).to eq([state2])
76
76
  end
77
77
 
@@ -103,7 +103,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
103
103
  it 'should complain when impossible predecessor of parse state' do
104
104
  subject.push_state(state1)
105
105
  subject.push_state(state2)
106
- allow(dotted_rule1).to receive(:prev_position).and_return(nil)
106
+ expect(dotted_rule1).to receive(:prev_position).and_return(nil)
107
107
  err = StandardError
108
108
  expect { subject.predecessor_state(state1) }.to raise_error(err)
109
109
  end
@@ -0,0 +1,81 @@
1
+ # Load the builder class
2
+ require_relative '../../../lib/rley/syntax/grammar_builder'
3
+ require_relative '../../../lib/rley/parser/token'
4
+
5
+
6
+ module GrammarL0Helper
7
+ ########################################
8
+ # Factory method. Define a grammar for a micro English-like language
9
+ # based on Jurafky & Martin L0 language (chapter 12 of the book).
10
+ # It defines the syntax of a sentence in a language with a
11
+ # very limited syntax and lexicon in the context of airline reservation.
12
+ def grammar_L0_builder()
13
+ builder = Rley::Syntax::GrammarBuilder.new
14
+ builder.add_terminals('Noun', 'Verb', 'Pronoun', 'Proper-Noun')
15
+ builder.add_terminals('Determiner', 'Preposition', )
16
+ builder.add_production('S' => %w[NP VP])
17
+ builder.add_production('NP' => 'Pronoun')
18
+ builder.add_production('NP' => 'Proper-Noun')
19
+ builder.add_production('NP' => %w[Determiner Nominal])
20
+ builder.add_production('Nominal' => %w[Nominal Noun])
21
+ builder.add_production('Nominal' => 'Noun')
22
+ builder.add_production('VP' => 'Verb')
23
+ builder.add_production('VP' => %w[Verb NP])
24
+ builder.add_production('VP' => %w[Verb NP PP])
25
+ builder.add_production('VP' => %w[Verb PP])
26
+ builder.add_production('PP' => %w[Preposition PP])
27
+ builder
28
+ end
29
+
30
+ # Return the language lexicon.
31
+ # A lexicon is just a Hash with pairs of the form:
32
+ # word => terminal symbol name
33
+ def lexicon_L0()
34
+ lexicon = {
35
+ 'flight' => 'Noun',
36
+ 'breeze' => 'Noun',
37
+ 'trip' => 'Noun',
38
+ 'morning' => 'Noun',
39
+ 'is' => 'Verb',
40
+ 'prefer' => 'Verb',
41
+ 'like' => 'Verb',
42
+ 'need' => 'Verb',
43
+ 'want' => 'Verb',
44
+ 'fly' => 'Verb',
45
+ 'me' => 'Pronoun',
46
+ 'I' => 'Pronoun',
47
+ 'you' => 'Pronoun',
48
+ 'it' => 'Pronoun',
49
+ 'Alaska' => 'Proper-Noun',
50
+ 'Baltimore' => 'Proper-Noun',
51
+ 'Chicago' => 'Proper-Noun',
52
+ 'United' => 'Proper-Noun',
53
+ 'American' => 'Proper-Noun',
54
+ 'the' => 'Determiner',
55
+ 'a' => 'Determiner',
56
+ 'an' => 'Determiner',
57
+ 'this' => 'Determiner',
58
+ 'these' => 'Determiner',
59
+ 'that' => 'Determiner',
60
+ 'from' => 'Preposition',
61
+ 'to' => 'Preposition',
62
+ 'on' => 'Preposition',
63
+ 'near' => 'Preposition'
64
+ }
65
+ end
66
+
67
+
68
+ # Highly simplified tokenizer implementation.
69
+ def tokenizer_L0(aText, aGrammar)
70
+ tokens = aText.scan(/\S+/).map do |word|
71
+ term_name = lexicon_L0[word]
72
+ if term_name.nil?
73
+ fail StandardError, "Word '#{word}' not found in lexicon"
74
+ end
75
+ terminal = aGrammar.name2symbol[term_name]
76
+ Rley::Parser::Token.new(word, terminal)
77
+ end
78
+
79
+ return tokens
80
+ end
81
+ end # module
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rley
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.01
4
+ version: 0.3.04
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-23 00:00:00.000000000 Z
11
+ date: 2016-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -36,40 +36,40 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '3.0'
39
+ version: '3.5'
40
40
  - - ">="
41
41
  - !ruby/object:Gem::Version
42
- version: 3.0.0
42
+ version: 3.5.0
43
43
  type: :development
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
47
  - - "~>"
48
48
  - !ruby/object:Gem::Version
49
- version: '3.0'
49
+ version: '3.5'
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
- version: 3.0.0
52
+ version: 3.5.0
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: simplecov
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '0.8'
59
+ version: '0.1'
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 0.8.0
62
+ version: 0.1.0
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '0.8'
69
+ version: '0.1'
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
- version: 0.8.0
72
+ version: 0.1.0
73
73
  - !ruby/object:Gem::Dependency
74
74
  name: coveralls
75
75
  requirement: !ruby/object:Gem::Requirement
@@ -249,12 +249,10 @@ files:
249
249
  - spec/rley/ptree/terminal_node_spec.rb
250
250
  - spec/rley/ptree/token_range_spec.rb
251
251
  - spec/rley/sppf/alternative_node_spec.rb
252
- - spec/rley/sppf/antecedence_graph.rb
253
- - spec/rley/sppf/forest_representation.rb
254
- - spec/rley/sppf/gfg_representation.rb
255
252
  - spec/rley/sppf/non_terminal_node_spec.rb
256
253
  - spec/rley/support/ambiguous_grammar_helper.rb
257
254
  - spec/rley/support/expectation_helper.rb
255
+ - spec/rley/support/grammar_L0_helper.rb
258
256
  - spec/rley/support/grammar_abc_helper.rb
259
257
  - spec/rley/support/grammar_b_expr_helper.rb
260
258
  - spec/rley/support/grammar_helper.rb
@@ -1,87 +0,0 @@
1
- # Mix-in module that generates a Graphviz's DOT file
2
- # that represents the precedence graph of parse entries.
3
- module AntecedenceGraph
4
-
5
- def generate_graph(aParsing, aFile)
6
- heading = build_heading()
7
- aFile.puts(heading)
8
-
9
- fill_graph(aParsing, aFile)
10
-
11
- trailing = build_trailing()
12
- aFile.puts(trailing)
13
- end
14
-
15
- private
16
-
17
- def build_heading()
18
- text = <<-END_STRING
19
- digraph entries {
20
- size = "7,9.5";
21
- page = "8.5,11";
22
- ratio = fill;
23
- rankdir = "BT"; // Draw arrows from bottom to top
24
- END_STRING
25
-
26
- return text
27
- end
28
-
29
- def build_trailing()
30
- return '}'
31
- end
32
-
33
- def fill_graph(aParsing, aFile)
34
- # Associate to each parse entry a node id
35
- oid2node_id = build_nodes_id(aParsing)
36
- aParsing.chart.sets.each_with_index do |entry_set, chart_index|
37
- # Create the graph nodes
38
- aFile.puts ''
39
- aFile.puts(cluster_heading(chart_index))
40
-
41
- entry_set.entries.each do |entry|
42
- aFile.puts %Q( #{oid2node_id[entry]}[label="#{entry}"];)
43
- end
44
- aFile.puts ' }' # Close cluster
45
-
46
- # Create the edges
47
- aFile.puts ''
48
- entry_set.entries.each do |entry|
49
- antecedents = aParsing.antecedence[entry]
50
- antecedents.each do |antec|
51
- aFile.puts " #{oid2node_id[antec]} -> #{oid2node_id[entry]};"
52
- end
53
- end
54
- end
55
- end
56
-
57
- # For each parse entry, associate a graph node id
58
- def build_nodes_id(aParsing)
59
- # Create a Hash with pairs of the form: object id => node id
60
- oid2node_id = {}
61
-
62
- aParsing.chart.sets.each_with_index do |entry_set, chart_index|
63
- entry_set.entries.each_with_index do |entry, entry_index|
64
- oid2node_id[entry] = "node_#{chart_index}_#{entry_index}"
65
- end
66
- end
67
-
68
- return oid2node_id
69
- end
70
-
71
-
72
- def cluster_heading(anIndex)
73
- text = <<-END_STRING
74
- subgraph cluster_chart_#{anIndex} {
75
- style = rounded;
76
- color = blue;
77
- fontsize = 24.0;
78
- labeljust = "r";
79
- label="chart[#{anIndex}]";
80
- END_STRING
81
-
82
- return text
83
- end
84
-
85
-
86
-
87
- end # module
@@ -1,136 +0,0 @@
1
- require 'set'
2
-
3
- # Mix-in module that generates a Graphviz's DOT file
4
- # that represents a parse forest.
5
- class ForestRepresentation
6
-
7
- def generate_graph(aPForest, aFile)
8
- heading = build_heading()
9
- aFile.puts(heading)
10
-
11
- fill_graph(aPForest, aFile)
12
-
13
- trailing = build_trailing()
14
- aFile.puts(trailing)
15
- end
16
-
17
- private
18
-
19
- def build_heading()
20
- text = <<-END_STRING
21
- digraph gfg {
22
- size="7,9.5";
23
- page="8.5,11";
24
- ratio = fill;
25
-
26
- END_STRING
27
-
28
- return text
29
- end
30
-
31
- def build_trailing()
32
- return '}'
33
- end
34
-
35
- def fill_graph(aPForest, aFile)
36
- visitees = Set.new
37
- visit_node(aPForest.root, aFile, visitees)
38
- end
39
-
40
- def visit_node(aNode, aFile, visitees)
41
- return if visitees.include?(aNode)
42
- visitees << aNode
43
- aFile.puts %Q( node_#{aNode.object_id}[shape=box, fontsize=18.0, label="#{aNode.to_string(0)}"];)
44
-
45
- if aNode.kind_of?(Rley::SPPF::CompositeNode)
46
- aNode.subnodes.each do |snode|
47
- # puts snode.to_string(0)
48
- next unless snode
49
- visit_node(snode, aFile, visitees)
50
- aFile.puts %Q( node_#{aNode.object_id} -> node_#{snode.object_id};)
51
- end
52
- end
53
- end
54
-
55
- =begin
56
- def fill_graph(aGFGraph, aFile)
57
- all_vertices = aGFGraph.vertices.dup
58
- (itemized, endpoints) = all_vertices.partition do |vertex|
59
- vertex.is_a?(Rley::GFG::ItemVertex)
60
- end
61
-
62
- # Group start/end nodes by non-terminal symbol
63
- group_endings = endpoints.group_by { |endpoint| endpoint.non_terminal }
64
-
65
- # Group item vertices by lhs non-terminal symbol
66
- group_items = itemized.group_by { |vertex| vertex.lhs }
67
-
68
- aFile.puts ''
69
- group_endings.each_pair do |nonterm, nodes|
70
- text = <<-END_STRING
71
- subgraph cluster_#{nonterm} {
72
- color = transparent;
73
- END_STRING
74
- aFile.puts text
75
- aFile.puts ' // Define the start and end nodes'
76
- nodes.each do |vertex|
77
- # Emit the start/end nodes
78
- aFile.puts %Q( node_#{vertex.object_id}[shape=box, fontsize=18.0, label="#{vertex.label}"];)
79
- end
80
-
81
- # Create sub-clusters by production
82
- subnodes = group_items[nonterm]
83
- subclusters = subnodes.group_by { |vertex| vertex.dotted_item.production }
84
- subclusters.each_pair do |prod, vertices|
85
- aFile.puts ''
86
- aFile.puts cluster_heading(prod)
87
- vertices.each do |vertex|
88
- aFile.puts %Q( node_#{vertex.object_id}[label="#{vertex.label}"];)
89
- end
90
- aFile.puts cluster_trailing(prod)
91
- end
92
- aFile.puts ' }'
93
- end
94
-
95
- aFile.puts ''
96
- aFile.puts ' // Draw the edges'
97
- aGFGraph.vertices.each do |from_vertex|
98
- from_vertex.edges.each do |anEdge|
99
- if from_vertex.is_a?(Rley::GFG::EndVertex)
100
- to_dotted_item = anEdge.successor.dotted_item
101
- label = "RET_#{to_dotted_item.production.object_id}_#{to_dotted_item.prev_position}"
102
- aFile.puts " node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id}[color=red, style=dashed, arrowhead=onormal,label=#{label}];"
103
- else
104
- if anEdge.is_a?(Rley::GFG::ScanEdge)
105
- aFile.puts %Q( node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id}[fontsize=18.0, label="#{anEdge.terminal}"];)
106
- else
107
- if anEdge.successor.is_a?(Rley::GFG::StartVertex)
108
- from_dotted_item = from_vertex.dotted_item
109
- label = "CALL_#{from_dotted_item.production.object_id}_#{from_dotted_item.position}"
110
- aFile.puts " node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id}[color=green, label=#{label}];"
111
- else
112
- aFile.puts " node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id};"
113
- end
114
- end
115
- end
116
- end
117
- end
118
- end
119
-
120
-
121
- def cluster_heading(anObject)
122
- text = <<-END_STRING
123
- subgraph cluster_#{anObject.object_id} {
124
- style = rounded;
125
- color = blue;
126
- END_STRING
127
-
128
- return text
129
- end
130
-
131
- def cluster_trailing(anObject)
132
- return ' }'
133
- end
134
- =end
135
-
136
- end # class