sequitur 0.1.23 → 0.1.24
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +11 -437
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +1 -1
- data/Rakefile +0 -2
- data/examples/integer_sample.rb +0 -1
- data/examples/porridge.rb +9 -9
- data/examples/word_sample.rb +4 -5
- data/lib/sequitur/constants.rb +4 -1
- data/lib/sequitur/digram.rb +2 -2
- data/lib/sequitur/dynamic_grammar.rb +3 -4
- data/lib/sequitur/formatter/base_formatter.rb +1 -1
- data/lib/sequitur/formatter/base_text.rb +3 -7
- data/lib/sequitur/formatter/debug.rb +0 -1
- data/lib/sequitur/grammar_visitor.rb +1 -1
- data/lib/sequitur/production.rb +200 -205
- data/lib/sequitur/production_ref.rb +9 -12
- data/lib/sequitur/sequitur_grammar.rb +135 -137
- data/lib/sequitur/symbol_sequence.rb +24 -27
- data/lib/sequitur.rb +4 -5
- data/spec/sequitur/digram_spec.rb +13 -12
- data/spec/sequitur/dynamic_grammar_spec.rb +5 -11
- data/spec/sequitur/formatter/base_text_spec.rb +70 -72
- data/spec/sequitur/formatter/debug_spec.rb +90 -92
- data/spec/sequitur/grammar_visitor_spec.rb +70 -71
- data/spec/sequitur/production_ref_spec.rb +92 -92
- data/spec/sequitur/production_spec.rb +30 -34
- data/spec/sequitur/sequitur_grammar_spec.rb +47 -46
- data/spec/sequitur/symbol_sequence_spec.rb +102 -105
- data/spec/spec_helper.rb +0 -1
- metadata +4 -5
- data/.travis.yml +0 -29
@@ -9,86 +9,84 @@ require_relative '../../../lib/sequitur/dynamic_grammar'
|
|
9
9
|
require_relative '../../../lib/sequitur/formatter/base_text'
|
10
10
|
|
11
11
|
module Sequitur # Re-open the module to get rid of qualified names
|
12
|
-
module Formatter
|
13
|
-
describe BaseText do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
module Formatter
|
13
|
+
describe BaseText do
|
14
|
+
# Factory method. Build a production with the given sequence
|
15
|
+
# of symbols as its rhs.
|
16
|
+
def build_production(*symbols)
|
17
|
+
prod = Production.new
|
18
|
+
symbols.each { |symb| prod.append_symbol(symb) }
|
19
|
+
prod
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
let(:p_a) { build_production(:a) }
|
23
|
+
let(:p_b) { build_production(:b) }
|
24
|
+
let(:p_c) { build_production(:c) }
|
25
|
+
let(:p_bc) { build_production(p_b, p_c) }
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
let(:empty_grammar) { DynamicGrammar.new }
|
28
|
+
let(:sample_grammar) do
|
29
|
+
grm = DynamicGrammar.new
|
30
|
+
grm.add_production(p_a)
|
31
|
+
grm.add_production(p_b)
|
32
|
+
grm.add_production(p_c)
|
33
|
+
grm.add_production(p_bc)
|
34
|
+
grm
|
35
|
+
end
|
36
36
|
|
37
|
-
|
37
|
+
let(:destination) { StringIO.new(+'', 'w') }
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
context 'Standard creation & initialization:' do
|
40
|
+
it 'should be initialized with an IO argument' do
|
41
|
+
expect { BaseText.new(StringIO.new(+'', 'w')) }.not_to raise_error
|
42
|
+
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
it 'should know its output destination' do
|
45
|
+
instance = BaseText.new(destination)
|
46
|
+
expect(instance.output).to eq(destination)
|
47
|
+
end
|
48
|
+
end # context
|
49
49
|
|
50
|
+
context 'Formatting events:' do
|
51
|
+
it 'should support events of an empty grammar' do
|
52
|
+
instance = BaseText.new(destination)
|
53
|
+
a_visitor = empty_grammar.visitor
|
54
|
+
instance.render(a_visitor)
|
55
|
+
expectations = <<~SNIPPET
|
56
|
+
start :.
|
57
|
+
SNIPPET
|
58
|
+
expect(destination.string).to eq(expectations)
|
59
|
+
end
|
50
60
|
|
61
|
+
it 'should support visit events with an explicit visitor' do
|
62
|
+
instance = BaseText.new(destination)
|
63
|
+
a_visitor = sample_grammar.visitor # Use visitor explicitly
|
64
|
+
instance.render(a_visitor)
|
65
|
+
expectations = <<~SNIPPET
|
66
|
+
start :.
|
67
|
+
P1 : a.
|
68
|
+
P2 : b.
|
69
|
+
P3 : c.
|
70
|
+
P4 : P2 P3.
|
71
|
+
SNIPPET
|
72
|
+
expect(destination.string).to eq(expectations)
|
73
|
+
end
|
51
74
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
expectations = <<-SNIPPET
|
68
|
-
start :.
|
69
|
-
P1 : a.
|
70
|
-
P2 : b.
|
71
|
-
P3 : c.
|
72
|
-
P4 : P2 P3.
|
73
|
-
SNIPPET
|
74
|
-
expect(destination.string).to eq(expectations)
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'should support visit events without an explicit visitor' do
|
78
|
-
instance = BaseText.new(destination)
|
79
|
-
instance.render(sample_grammar)
|
80
|
-
expectations = <<-SNIPPET
|
81
|
-
start :.
|
82
|
-
P1 : a.
|
83
|
-
P2 : b.
|
84
|
-
P3 : c.
|
85
|
-
P4 : P2 P3.
|
86
|
-
SNIPPET
|
87
|
-
expect(destination.string).to eq(expectations)
|
88
|
-
end
|
89
|
-
end # context
|
90
|
-
end # describe
|
91
|
-
end # module
|
75
|
+
it 'should support visit events without an explicit visitor' do
|
76
|
+
instance = BaseText.new(destination)
|
77
|
+
instance.render(sample_grammar)
|
78
|
+
expectations = <<~SNIPPET
|
79
|
+
start :.
|
80
|
+
P1 : a.
|
81
|
+
P2 : b.
|
82
|
+
P3 : c.
|
83
|
+
P4 : P2 P3.
|
84
|
+
SNIPPET
|
85
|
+
expect(destination.string).to eq(expectations)
|
86
|
+
end
|
87
|
+
end # context
|
88
|
+
end # describe
|
89
|
+
end # module
|
92
90
|
end # module
|
93
91
|
|
94
92
|
# End of file
|
@@ -9,105 +9,103 @@ require_relative '../../../lib/sequitur/dynamic_grammar'
|
|
9
9
|
require_relative '../../../lib/sequitur/formatter/debug'
|
10
10
|
|
11
11
|
module Sequitur # Re-open the module to get rid of qualified names
|
12
|
-
module Formatter
|
13
|
-
describe Debug do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
module Formatter
|
13
|
+
describe Debug do
|
14
|
+
# Factory method. Build a production with the given sequence
|
15
|
+
# of symbols as its rhs.
|
16
|
+
def build_production(*symbols)
|
17
|
+
prod = Production.new
|
18
|
+
symbols.each { |symb| prod.append_symbol(symb) }
|
19
|
+
prod
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
let(:p_a) { build_production(:a) }
|
23
|
+
let(:p_b) { build_production(:b) }
|
24
|
+
let(:p_c) { build_production(:c) }
|
25
|
+
let(:p_bc) { build_production(p_b, p_c) }
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
let(:empty_grammar) { DynamicGrammar.new }
|
28
|
+
let(:sample_grammar) do
|
29
|
+
grm = DynamicGrammar.new
|
30
|
+
grm.add_production(p_a)
|
31
|
+
grm.add_production(p_b)
|
32
|
+
grm.add_production(p_c)
|
33
|
+
grm.add_production(p_bc)
|
34
|
+
grm
|
35
|
+
end
|
36
36
|
|
37
|
-
|
37
|
+
let(:destination) { StringIO.new(+'', 'w') }
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
context 'Standard creation & initialization:' do
|
40
|
+
it 'should be initialized with an IO argument' do
|
41
|
+
expect { Debug.new(StringIO.new(+'', 'w')) }.not_to raise_error
|
42
|
+
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
it 'should know its output destination' do
|
45
|
+
instance = Debug.new(destination)
|
46
|
+
expect(instance.output).to eq(destination)
|
47
|
+
end
|
48
|
+
end # context
|
49
49
|
|
50
|
+
context 'Formatting events:' do
|
51
|
+
it 'should support events of an empty grammar' do
|
52
|
+
instance = Debug.new(destination)
|
53
|
+
a_visitor = empty_grammar.visitor
|
54
|
+
instance.render(a_visitor)
|
55
|
+
expectations = <<~SNIPPET
|
56
|
+
before_grammar
|
57
|
+
before_production
|
58
|
+
before_rhs
|
59
|
+
after_rhs
|
60
|
+
after_production
|
61
|
+
after_grammar
|
62
|
+
SNIPPET
|
63
|
+
expect(destination.string).to eq(expectations)
|
64
|
+
end
|
50
65
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
after_rhs
|
95
|
-
after_production
|
96
|
-
before_production
|
97
|
-
before_rhs
|
98
|
-
before_non_terminal
|
99
|
-
after_non_terminal
|
100
|
-
before_non_terminal
|
101
|
-
after_non_terminal
|
102
|
-
after_rhs
|
103
|
-
after_production
|
104
|
-
after_grammar
|
105
|
-
SNIPPET
|
106
|
-
expect(destination.string).to eq(expectations)
|
107
|
-
end
|
108
|
-
end # context
|
109
|
-
end # describe
|
110
|
-
end # module
|
66
|
+
it 'should support events of a non-empty grammar' do
|
67
|
+
instance = Debug.new(destination)
|
68
|
+
a_visitor = sample_grammar.visitor
|
69
|
+
instance.render(a_visitor)
|
70
|
+
expectations = <<~SNIPPET
|
71
|
+
before_grammar
|
72
|
+
before_production
|
73
|
+
before_rhs
|
74
|
+
after_rhs
|
75
|
+
after_production
|
76
|
+
before_production
|
77
|
+
before_rhs
|
78
|
+
before_terminal
|
79
|
+
after_terminal
|
80
|
+
after_rhs
|
81
|
+
after_production
|
82
|
+
before_production
|
83
|
+
before_rhs
|
84
|
+
before_terminal
|
85
|
+
after_terminal
|
86
|
+
after_rhs
|
87
|
+
after_production
|
88
|
+
before_production
|
89
|
+
before_rhs
|
90
|
+
before_terminal
|
91
|
+
after_terminal
|
92
|
+
after_rhs
|
93
|
+
after_production
|
94
|
+
before_production
|
95
|
+
before_rhs
|
96
|
+
before_non_terminal
|
97
|
+
after_non_terminal
|
98
|
+
before_non_terminal
|
99
|
+
after_non_terminal
|
100
|
+
after_rhs
|
101
|
+
after_production
|
102
|
+
after_grammar
|
103
|
+
SNIPPET
|
104
|
+
expect(destination.string).to eq(expectations)
|
105
|
+
end
|
106
|
+
end # context
|
107
|
+
end # describe
|
108
|
+
end # module
|
111
109
|
end # module
|
112
110
|
|
113
111
|
# End of file
|
@@ -6,77 +6,76 @@ require_relative '../spec_helper'
|
|
6
6
|
require_relative '../../lib/sequitur/grammar_visitor'
|
7
7
|
|
8
8
|
module Sequitur # Re-open the module to get rid of qualified names
|
9
|
-
describe GrammarVisitor do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
78
|
-
end #
|
79
|
-
end # describe
|
9
|
+
describe GrammarVisitor do
|
10
|
+
# Use a double(mock) as a grammar
|
11
|
+
let(:fake) { double('fake-grammar') }
|
12
|
+
|
13
|
+
context 'Standard creation & initialization:' do
|
14
|
+
# Default instantiation rule
|
15
|
+
subject { GrammarVisitor.new(fake) }
|
16
|
+
|
17
|
+
it 'should be initialized with a grammar argument' do
|
18
|
+
expect { GrammarVisitor.new(fake) }.not_to raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should know the grammar to visit' do
|
22
|
+
expect(subject.grammar).to eq(fake)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "shouldn't have subscribers at start" do
|
26
|
+
expect(subject.subscribers).to be_empty
|
27
|
+
end
|
28
|
+
end # context
|
29
|
+
|
30
|
+
context 'Subscribing:' do
|
31
|
+
# Default instantiation rule
|
32
|
+
subject { GrammarVisitor.new(fake) }
|
33
|
+
|
34
|
+
let(:listener1) { double('fake-formatter1') }
|
35
|
+
let(:listener2) { double('fake-formatter2') }
|
36
|
+
|
37
|
+
it 'should allow subscriptions' do
|
38
|
+
subject.subscribe(listener1)
|
39
|
+
expect(subject.subscribers.size).to eq(1)
|
40
|
+
expect(subject.subscribers).to eq([listener1])
|
41
|
+
|
42
|
+
subject.subscribe(listener2)
|
43
|
+
expect(subject.subscribers.size).to eq(2)
|
44
|
+
expect(subject.subscribers).to eq([listener1, listener2])
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should allow un-subcriptions' do
|
48
|
+
subject.subscribe(listener1)
|
49
|
+
subject.subscribe(listener2)
|
50
|
+
subject.unsubscribe(listener2)
|
51
|
+
expect(subject.subscribers.size).to eq(1)
|
52
|
+
expect(subject.subscribers).to eq([listener1])
|
53
|
+
subject.unsubscribe(listener1)
|
54
|
+
expect(subject.subscribers).to be_empty
|
55
|
+
end
|
56
|
+
end # context
|
57
|
+
|
58
|
+
context 'Notifying visit events:' do
|
59
|
+
# Default instantiation rule
|
60
|
+
subject do
|
61
|
+
instance = GrammarVisitor.new(fake)
|
62
|
+
instance.subscribe(listener1)
|
63
|
+
instance
|
64
|
+
end
|
65
|
+
|
66
|
+
# Use doubles/mocks to simulate formatters
|
67
|
+
let(:listener1) { double('fake-formatter1') }
|
68
|
+
let(:listener2) { double('fake-formatter2') }
|
69
|
+
let(:mock_production) { double('fake-production') }
|
70
|
+
|
71
|
+
it 'should react to the start_visit_grammar message' do
|
72
|
+
# Notify subscribers when start the visit of the grammar
|
73
|
+
expect(listener1).to receive(:before_grammar).with(fake)
|
74
|
+
|
75
|
+
subject.start_visit_grammar(fake)
|
76
|
+
end
|
77
|
+
end # context
|
78
|
+
end # describe
|
80
79
|
end # module
|
81
80
|
|
82
81
|
# End of file
|