sequitur 0.1.18 → 0.1.19

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.
@@ -23,7 +23,7 @@ class Production
23
23
 
24
24
  # Constructor.
25
25
  # Build a production with an empty RHS.
26
- def initialize()
26
+ def initialize
27
27
  @rhs = SymbolSequence.new
28
28
  @refcount = 0
29
29
  @digrams = []
@@ -44,7 +44,6 @@ class Production
44
44
  return result
45
45
  end
46
46
 
47
-
48
47
  # Is the rhs empty?
49
48
  # @ return true if the rhs has no members.
50
49
  def empty?
@@ -52,20 +51,19 @@ class Production
52
51
  end
53
52
 
54
53
  # Increment the reference count by one.
55
- def incr_refcount()
54
+ def incr_refcount
56
55
  @refcount += 1
57
56
  end
58
57
 
59
58
  # Decrement the reference count by one.
60
- def decr_refcount()
59
+ def decr_refcount
61
60
  raise StandardError, 'Internal error' if @refcount.zero?
62
61
  @refcount -= 1
63
62
  end
64
63
 
65
-
66
64
  # Select the references to production appearing in the rhs.
67
65
  # @return [Array of ProductionRef]
68
- def references()
66
+ def references
69
67
  return rhs.references
70
68
  end
71
69
 
@@ -77,10 +75,9 @@ class Production
77
75
  return rhs.references_of(real_prod)
78
76
  end
79
77
 
80
-
81
78
  # Enumerate the digrams appearing in the right-hand side (rhs)
82
79
  # @return [Array] the list of digrams found in rhs of this production.
83
- def recalc_digrams()
80
+ def recalc_digrams
84
81
  return [] if rhs.size < 2
85
82
 
86
83
  result = []
@@ -88,20 +85,17 @@ class Production
88
85
  @digrams = result
89
86
  end
90
87
 
91
-
92
-
93
88
  # Does the rhs have exactly one digram only (= 2 symbols)?
94
89
  # @return [true/false] true when the rhs contains exactly two symbols.
95
90
  def single_digram?
96
91
  return rhs.size == 2
97
92
  end
98
93
 
99
-
100
94
  # Detect whether the last digram occurs twice
101
95
  # Assumption: when a digram occurs twice in a production then it must occur
102
96
  # at the end of the rhs
103
97
  # @return [true/false] true when the digram occurs twice in rhs.
104
- def repeated_digram?()
98
+ def repeated_digram?
105
99
  return false if rhs.size < 3
106
100
 
107
101
  my_digrams = digrams
@@ -113,17 +107,16 @@ class Production
113
107
 
114
108
  # Retrieve the last digram appearing in the RHS (if any).
115
109
  # @return [Digram] last digram in the rhs otherwise nil.
116
- def last_digram()
110
+ def last_digram
117
111
  result = digrams.empty? ? nil : digrams.last
118
112
  return result
119
113
  end
120
114
 
121
-
122
115
  # Emit a text representation of the production rule.
123
116
  # Text is of the form:
124
117
  # object id of production : rhs as space-separated sequence of symbols.
125
118
  # @return [String]
126
- def to_string()
119
+ def to_string
127
120
  return "#{object_id} : #{rhs.to_string}."
128
121
  end
129
122
 
@@ -150,7 +143,7 @@ class Production
150
143
 
151
144
  # Clear the right-hand side.
152
145
  # Any referenced production has its reference counter decremented.
153
- def clear_rhs()
146
+ def clear_rhs
154
147
  rhs.clear
155
148
  end
156
149
 
@@ -168,7 +161,7 @@ class Production
168
161
  # p.positions_of(a, a) # => [0, 3]
169
162
  def positions_of(symb1, symb2)
170
163
  # Find the positions where the digram occur in rhs
171
- indices = [ -2 ] # Dummy index!
164
+ indices = [-2] # Dummy index!
172
165
  (0...rhs.size).each do |i|
173
166
  next if i == indices.last + 1
174
167
  indices << i if (rhs[i] == symb1) && (rhs[i + 1] == symb2)
@@ -179,7 +172,6 @@ class Production
179
172
  return indices
180
173
  end
181
174
 
182
-
183
175
  # Given that the production P passed as argument has exactly 2 symbols
184
176
  # in its rhs s1 s2, substitute in the rhs of self all occurrences of
185
177
  # s1 s2 by a reference to P.
@@ -217,7 +209,6 @@ class Production
217
209
  recalc_digrams
218
210
  end
219
211
 
220
-
221
212
  # Part of the 'visitee' role in Visitor design pattern.
222
213
  # @param aVisitor[GrammarVisitor]
223
214
  def accept(aVisitor)
@@ -1,115 +1,114 @@
1
1
 
2
2
 
3
3
  module Sequitur # Module for classes implementing the Sequitur algorithm
4
- # A production reference is a grammar symbol that may appear in the right-hand
5
- # side of a production P1 and that refers to a production P2.
6
- # Every time a production P2 appears in the left-hand side of
7
- # production P1, this is implemented by inserting a production reference to P2
8
- # in the appropriate position in the RHS of P1.
9
- # In the literature, production references are also called non terminal
10
- # symbols
11
- # @example
12
- # # Given a production rule...
13
- # prod = Sequitur::Production.new
14
- # puts prod.refcount # outputs 0
15
- # # ... Build a reference to it
16
- # ref = Sequitur::ProductionRef.new(prod)
17
- # # ... Production reference count is updated...
18
- # puts prod.refcount # outputs 1
19
- class ProductionRef
20
- # Link to the production to reference.
21
- attr_reader(:production)
22
-
23
- # Constructor
24
- # @param target [Production or ProductionRef]
25
- # The production that is being referenced.
26
- def initialize(target)
27
- bind_to(target)
28
- end
29
-
30
- # Copy constructor invoked by dup or clone methods.
31
- # @param orig [ProductionRef]
4
+ # A production reference is a grammar symbol that may appear in the right-hand
5
+ # side of a production P1 and that refers to a production P2.
6
+ # Every time a production P2 appears in the left-hand side of
7
+ # production P1, this is implemented by inserting a production reference to P2
8
+ # in the appropriate position in the RHS of P1.
9
+ # In the literature, production references are also called non terminal
10
+ # symbols
32
11
  # @example
12
+ # # Given a production rule...
33
13
  # prod = Sequitur::Production.new
14
+ # puts prod.refcount # outputs 0
15
+ # # ... Build a reference to it
34
16
  # ref = Sequitur::ProductionRef.new(prod)
35
- # copy_ref = ref.dup
36
- # puts prod.refcount # outputs 2
37
- def initialize_copy(orig)
38
- @production = nil
39
- bind_to(orig.production)
40
- end
41
-
42
- # Emit the text representation of a production reference.
43
- # @return [String]
44
- def to_s()
45
- return production.object_id.to_s
46
- end
47
-
48
- alias to_string to_s
49
-
50
-
51
- # Equality testing.
52
- # A production ref is equal to another one when its
53
- # refers to the same production or when it is compared to
54
- # the production it refers to.
55
- # @param other [ProductionRef]
56
- # @return [true / false]
57
- def ==(other)
58
- return true if object_id == other.object_id
59
-
60
- result = if other.is_a?(ProductionRef)
61
- (production == other.production)
62
- else
63
- (production == other)
64
- end
65
-
66
- return result
67
- end
68
-
69
- # Produce a hash value.
70
- # A reference has no identity on its own,
71
- # the method returns the hash value of the
72
- # referenced production
73
- # @return [Fixnum] the hash value
74
- def hash()
75
- raise StandardError, 'Nil production' if production.nil?
76
- return production.hash
77
- end
78
-
79
- # Make this reference point to the given production.
80
- # @param aProduction [Production or ProductionRef] the production
81
- # to refer to
82
- def bind_to(aProduction)
83
- return if aProduction == @production
84
-
85
- production.decr_refcount if production
86
- unless aProduction.kind_of?(Production)
87
- raise StandardError, "Illegal production type #{aProduction.class}"
17
+ # # ... Production reference count is updated...
18
+ # puts prod.refcount # outputs 1
19
+ class ProductionRef
20
+ # Link to the production to reference.
21
+ attr_reader(:production)
22
+
23
+ # Constructor
24
+ # @param target [Production or ProductionRef]
25
+ # The production that is being referenced.
26
+ def initialize(target)
27
+ bind_to(target)
88
28
  end
89
- @production = aProduction
90
- production.incr_refcount
91
- end
92
-
93
-
94
- # Clear the reference to the target production.
95
- def unbind()
96
- production.decr_refcount
97
- @production = nil
98
- end
99
-
100
- # Check that the this object doesn't refer to any production.
101
- # @return [true / false] true when this object doesn't
102
- # point to a production.
103
- def unbound?()
104
- return production.nil?
105
- end
106
-
107
- # Part of the 'visitee' role in the Visitor design pattern.
108
- # @param aVisitor [GrammarVisitor] the visitor
109
- def accept(aVisitor)
110
- aVisitor.visit_prod_ref(self)
111
- end
112
- end # class
29
+
30
+ # Copy constructor invoked by dup or clone methods.
31
+ # @param orig [ProductionRef]
32
+ # @example
33
+ # prod = Sequitur::Production.new
34
+ # ref = Sequitur::ProductionRef.new(prod)
35
+ # copy_ref = ref.dup
36
+ # puts prod.refcount # outputs 2
37
+ def initialize_copy(orig)
38
+ @production = nil
39
+ bind_to(orig.production)
40
+ end
41
+
42
+ # Emit the text representation of a production reference.
43
+ # @return [String]
44
+ def to_s
45
+ return production.object_id.to_s
46
+ end
47
+
48
+ alias to_string to_s
49
+
50
+
51
+ # Equality testing.
52
+ # A production ref is equal to another one when its
53
+ # refers to the same production or when it is compared to
54
+ # the production it refers to.
55
+ # @param other [ProductionRef]
56
+ # @return [true / false]
57
+ def ==(other)
58
+ return true if object_id == other.object_id
59
+
60
+ result = if other.is_a?(ProductionRef)
61
+ (production == other.production)
62
+ else
63
+ (production == other)
64
+ end
65
+
66
+ return result
67
+ end
68
+
69
+ # Produce a hash value.
70
+ # A reference has no identity on its own,
71
+ # the method returns the hash value of the
72
+ # referenced production
73
+ # @return [Fixnum] the hash value
74
+ def hash
75
+ raise StandardError, 'Nil production' if production.nil?
76
+ return production.hash
77
+ end
78
+
79
+ # Make this reference point to the given production.
80
+ # @param aProduction [Production or ProductionRef] the production
81
+ # to refer to
82
+ def bind_to(aProduction)
83
+ return if aProduction == @production
84
+
85
+ production.decr_refcount if production
86
+ unless aProduction.kind_of?(Production)
87
+ raise StandardError, "Illegal production type #{aProduction.class}"
88
+ end
89
+ @production = aProduction
90
+ production.incr_refcount
91
+ end
92
+
93
+ # Clear the reference to the target production.
94
+ def unbind
95
+ production.decr_refcount
96
+ @production = nil
97
+ end
98
+
99
+ # Check that the this object doesn't refer to any production.
100
+ # @return [true / false] true when this object doesn't
101
+ # point to a production.
102
+ def unbound?
103
+ return production.nil?
104
+ end
105
+
106
+ # Part of the 'visitee' role in the Visitor design pattern.
107
+ # @param aVisitor [GrammarVisitor] the visitor
108
+ def accept(aVisitor)
109
+ aVisitor.visit_prod_ref(self)
110
+ end
111
+ end # class
113
112
  end # module
114
113
 
115
114
  # End of file
@@ -43,7 +43,7 @@ class SequiturGrammar < DynamicGrammar
43
43
  # remove P from grammar
44
44
  # end
45
45
  # end until digram unicity and rule utility are met
46
- def enforce_rules()
46
+ def enforce_rules
47
47
  loop do
48
48
  unicity_diagnosis = detect_collision if unicity_diagnosis.nil?
49
49
  restore_unicity(unicity_diagnosis) if unicity_diagnosis.collision_found
@@ -61,7 +61,7 @@ class SequiturGrammar < DynamicGrammar
61
61
  # Return an empty Hash if each digram appears once.
62
62
  # Otherwise return a Hash with a pair of the form: digram => [Pi, Pk]
63
63
  # Where Pi, Pk are two productions where the digram occurs.
64
- def detect_collision()
64
+ def detect_collision
65
65
  diagnosis = CollisionDiagnosis.new(false)
66
66
  found_so_far = {}
67
67
  productions.each do |a_prod|
@@ -109,7 +109,7 @@ class SequiturGrammar < DynamicGrammar
109
109
  end
110
110
 
111
111
  # Return a production that is used less than twice in the grammar.
112
- def detect_useless_production()
112
+ def detect_useless_production
113
113
  useless = productions.index { |prod| prod.refcount < 2 }
114
114
  useless = nil if useless && useless.zero?
115
115
 
@@ -6,7 +6,7 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
6
6
  attr_reader(:symbols)
7
7
 
8
8
  # Create an empty sequence
9
- def initialize()
9
+ def initialize
10
10
  @symbols = []
11
11
  end
12
12
 
@@ -21,7 +21,7 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
21
21
  end
22
22
 
23
23
  # Clear the symbol sequence.
24
- def clear()
24
+ def clear
25
25
  refs = references
26
26
  refs.each(&:unbind)
27
27
  @symbols = []
@@ -30,13 +30,13 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
30
30
 
31
31
  # Tell whether the sequence is empty.
32
32
  # @return [true / false] true only if the sequence has no symbol in it.
33
- def empty?()
33
+ def empty?
34
34
  return symbols.empty?
35
35
  end
36
36
 
37
37
  # Count the number of elements in the sequence.
38
38
  # @return [Fixnum] the number of elements
39
- def size()
39
+ def size
40
40
  return symbols.size
41
41
  end
42
42
 
@@ -76,15 +76,13 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
76
76
  return same
77
77
  end
78
78
 
79
-
80
79
  # Select the references to production appearing in the rhs.
81
80
  # @return [Array of ProductionRef]
82
- def references()
81
+ def references
83
82
  @memo_references ||= symbols.select { |symb| symb.is_a?(ProductionRef) }
84
83
  return @memo_references
85
84
  end
86
85
 
87
-
88
86
  # Select the references of the given production appearing in the rhs.
89
87
  # @param aProduction [Production]
90
88
  # @return [Array of ProductionRef]
@@ -94,11 +92,10 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
94
92
  return result
95
93
  end
96
94
 
97
-
98
95
  # Emit a text representation of the symbol sequence.
99
96
  # Text is of the form: space-separated sequence of symbols.
100
97
  # @return [String]
101
- def to_string()
98
+ def to_string
102
99
  rhs_text = symbols.map do |elem|
103
100
  case elem
104
101
  when String then "'#{elem}'"
@@ -150,7 +147,6 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
150
147
  symbols.delete_at(position)
151
148
  end
152
149
 
153
-
154
150
  # Part of the 'visitee' role in Visitor design pattern.
155
151
  # @param aVisitor[GrammarVisitor]
156
152
  def accept(aVisitor)
@@ -170,7 +166,7 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
170
166
 
171
167
  private
172
168
 
173
- def invalidate_refs()
169
+ def invalidate_refs
174
170
  @memo_references = nil
175
171
  @lookup_references = nil
176
172
  end
@@ -5,28 +5,28 @@ require_relative '../../lib/sequitur/digram'
5
5
 
6
6
  module Sequitur # Re-open the module to get rid of qualified names
7
7
  describe Digram do
8
- let(:two_symbols) { [:b, :c] }
8
+ let(:two_symbols) { %i[b c] }
9
9
  let(:production) { double('sample-production') }
10
10
 
11
11
  context 'Standard creation & initialization:' do
12
12
  it 'should be created with 3 arguments' do
13
13
  instance = Digram.new(:b, :c, production)
14
-
14
+
15
15
  expect(instance.symbols).to eq(two_symbols)
16
16
  expect(instance.production).to eq(production)
17
17
  end
18
-
18
+
19
19
  it 'should return the production that it refers to' do
20
20
  instance = Digram.new(:b, :c, production)
21
21
  expect(instance.production).to eq(production)
22
22
  end
23
-
23
+
24
24
  it 'should whether its symbols are the same' do
25
25
  instance1 = Digram.new(:a, :a, production)
26
26
  expect(instance1).to be_repeating
27
-
27
+
28
28
  instance1 = Digram.new(:a, :b, production)
29
- expect(instance1).not_to be_repeating
29
+ expect(instance1).not_to be_repeating
30
30
  end
31
31
  end # context
32
32
 
@@ -35,11 +35,11 @@ describe Digram do
35
35
  instance1 = Digram.new(:a, :b, production)
36
36
  same = Digram.new(:a, :b, production)
37
37
  different = Digram.new(:b, :c, production)
38
-
38
+
39
39
  expect(instance1).to eq(instance1)
40
40
  expect(instance1).to eq(same)
41
41
  expect(instance1).not_to eq(different)
42
- expect(same).not_to eq(different)
42
+ expect(same).not_to eq(different)
43
43
  end
44
44
  end # context
45
45
  end # describe