rley 0.0.04 → 0.0.05
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 +8 -8
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/parser/chart.rb +2 -4
- data/lib/rley/parser/dotted_item.rb +2 -4
- data/lib/rley/parser/earley_parser.rb +13 -16
- data/lib/rley/parser/parse_state.rb +2 -5
- data/lib/rley/parser/parsing.rb +17 -20
- data/lib/rley/parser/state_set.rb +1 -5
- data/lib/rley/parser/token.rb +0 -4
- data/lib/rley/syntax/grammar.rb +1 -4
- data/lib/rley/syntax/grm_symbol.rb +0 -2
- data/lib/rley/syntax/literal.rb +0 -2
- data/lib/rley/syntax/non_terminal.rb +0 -4
- data/lib/rley/syntax/production.rb +3 -7
- data/lib/rley/syntax/symbol_seq.rb +7 -8
- data/lib/rley/syntax/verbatim_symbol.rb +0 -2
- data/spec/rley/parser/chart_spec.rb +24 -26
- data/spec/rley/parser/dotted_item_spec.rb +83 -88
- data/spec/rley/parser/earley_parser_spec.rb +277 -241
- data/spec/rley/parser/parse_state_spec.rb +66 -66
- data/spec/rley/parser/parsing_spec.rb +89 -90
- data/spec/rley/parser/state_set_spec.rb +54 -56
- data/spec/rley/parser/token_spec.rb +18 -20
- data/spec/rley/syntax/grammar_spec.rb +118 -120
- data/spec/rley/syntax/grm_symbol_spec.rb +12 -15
- data/spec/rley/syntax/literal_spec.rb +16 -18
- data/spec/rley/syntax/non_terminal_spec.rb +12 -15
- data/spec/rley/syntax/production_spec.rb +33 -35
- data/spec/rley/syntax/symbol_seq_spec.rb +51 -52
- data/spec/rley/syntax/terminal_spec.rb +12 -15
- data/spec/rley/syntax/verbatim_symbol_spec.rb +16 -18
- metadata +2 -2
@@ -10,90 +10,90 @@ require_relative '../../../lib/rley/parser/parse_state'
|
|
10
10
|
|
11
11
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
12
12
|
module Parser # Open this namespace to avoid module qualifier prefixes
|
13
|
+
describe ParseState do
|
13
14
|
|
14
|
-
|
15
|
+
let(:t_a) { Syntax::Terminal.new('A') }
|
16
|
+
let(:t_b) { Syntax::Terminal.new('B') }
|
17
|
+
let(:t_c) { Syntax::Terminal.new('C') }
|
18
|
+
let(:nt_sentence) { Syntax::NonTerminal.new('sentence') }
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
let(:nt_sentence) { Syntax::NonTerminal.new('sentence') }
|
20
|
+
let(:sample_prod) do
|
21
|
+
Syntax::Production.new(nt_sentence, [t_a, t_b, t_c])
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
let(:other_prod) do
|
25
|
+
Syntax::Production.new(nt_sentence, [t_a])
|
26
|
+
end
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
let(:empty_prod) do
|
30
|
-
Syntax::Production.new(nt_sentence,[])
|
31
|
-
end
|
32
|
-
|
33
|
-
let(:origin_val) { 3 }
|
34
|
-
let(:dotted_rule) { DottedItem.new(sample_prod, 2) }
|
35
|
-
let(:other_dotted_rule) { double('mock-dotted-item') }
|
28
|
+
let(:empty_prod) do
|
29
|
+
Syntax::Production.new(nt_sentence, [])
|
30
|
+
end
|
36
31
|
|
37
|
-
|
38
|
-
|
32
|
+
let(:origin_val) { 3 }
|
33
|
+
let(:dotted_rule) { DottedItem.new(sample_prod, 2) }
|
34
|
+
let(:other_dotted_rule) { double('mock-dotted-item') }
|
39
35
|
|
40
|
-
|
36
|
+
# Default instantiation rule
|
37
|
+
subject { ParseState.new(dotted_rule, origin_val) }
|
41
38
|
|
42
|
-
|
43
|
-
expect { ParseState.new(dotted_rule, origin_val) }.not_to raise_error
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'should complain when the dotted rule is nil' do
|
47
|
-
err = StandardError
|
48
|
-
msg = 'Dotted item cannot be nil'
|
49
|
-
expect { ParseState.new(nil, 2) }.to raise_error(err, msg)
|
50
|
-
end
|
39
|
+
context 'Initialization:' do
|
51
40
|
|
52
|
-
|
53
|
-
|
54
|
-
|
41
|
+
it 'should be created with a dotted item and a origin position' do
|
42
|
+
args = [dotted_rule, origin_val]
|
43
|
+
expect { ParseState.new(*args) }.not_to raise_error
|
44
|
+
end
|
55
45
|
|
56
|
-
|
57
|
-
|
58
|
-
|
46
|
+
it 'should complain when the dotted rule is nil' do
|
47
|
+
err = StandardError
|
48
|
+
msg = 'Dotted item cannot be nil'
|
49
|
+
expect { ParseState.new(nil, 2) }.to raise_error(err, msg)
|
50
|
+
end
|
59
51
|
|
52
|
+
it 'should know the related dotted rule' do
|
53
|
+
expect(subject.dotted_rule).to eq(dotted_rule)
|
54
|
+
end
|
60
55
|
|
61
|
-
|
56
|
+
it 'should know the origin value' do
|
57
|
+
expect(subject.origin).to eq(origin_val)
|
58
|
+
end
|
62
59
|
|
63
|
-
context 'Provided services:' do
|
64
|
-
it 'should compare with itself' do
|
65
|
-
expect(subject == subject).to eq(true)
|
66
|
-
end
|
67
60
|
|
68
|
-
|
69
|
-
equal = ParseState.new(dotted_rule, origin_val)
|
70
|
-
expect(subject == equal).to eq(true)
|
61
|
+
end # context
|
71
62
|
|
72
|
-
|
73
|
-
|
74
|
-
|
63
|
+
context 'Provided services:' do
|
64
|
+
it 'should compare with itself' do
|
65
|
+
synonym = subject # Fool Rubocop
|
66
|
+
expect(subject == synonym).to eq(true)
|
67
|
+
end
|
75
68
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'should know if the parsing reached the end of the production' do
|
82
|
-
expect(subject).not_to be_complete
|
83
|
-
at_end = DottedItem.new(sample_prod, 3)
|
69
|
+
it 'should compare with another' do
|
70
|
+
equal = ParseState.new(dotted_rule, origin_val)
|
71
|
+
expect(subject == equal).to eq(true)
|
84
72
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
73
|
+
# Same dotted_rule, different origin
|
74
|
+
diff_origin = ParseState.new(dotted_rule, 2)
|
75
|
+
expect(subject == diff_origin).to eq(false)
|
76
|
+
|
77
|
+
# Different dotted item, same origin
|
78
|
+
diff_rule = ParseState.new(other_dotted_rule, 3)
|
79
|
+
expect(subject == diff_rule).to eq(false)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should know if the parsing reached the end of the production' do
|
83
|
+
expect(subject).not_to be_complete
|
84
|
+
at_end = DottedItem.new(sample_prod, 3)
|
85
|
+
|
86
|
+
instance = ParseState.new(at_end, 2)
|
87
|
+
expect(instance).to be_complete
|
88
|
+
end
|
93
89
|
|
94
|
-
|
90
|
+
it 'should know the next expected symbol' do
|
91
|
+
expect(subject.next_symbol).to eq(t_c)
|
92
|
+
end
|
93
|
+
end # context
|
95
94
|
|
95
|
+
end # describe
|
96
96
|
end # module
|
97
97
|
end # module
|
98
98
|
|
99
|
-
# End of file
|
99
|
+
# End of file
|
@@ -10,109 +10,108 @@ require_relative '../../../lib/rley/parser/parsing'
|
|
10
10
|
|
11
11
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
12
12
|
module Parser # Open this namespace to avoid module qualifier prefixes
|
13
|
+
describe Parsing do
|
13
14
|
|
14
|
-
|
15
|
+
# Grammar 1: A very simple language
|
16
|
+
# S ::= A.
|
17
|
+
# A ::= "a" A "c".
|
18
|
+
# A ::= "b".
|
19
|
+
let(:nt_S) { Syntax::NonTerminal.new('S') }
|
20
|
+
let(:nt_A) { Syntax::NonTerminal.new('A') }
|
21
|
+
let(:a_) { Syntax::VerbatimSymbol.new('a') }
|
22
|
+
let(:b_) { Syntax::VerbatimSymbol.new('b') }
|
23
|
+
let(:c_) { Syntax::VerbatimSymbol.new('c') }
|
24
|
+
let(:prod_S) { Syntax::Production.new(nt_S, [nt_A]) }
|
25
|
+
let(:prod_A1) { Syntax::Production.new(nt_A, [a_, nt_A, c_]) }
|
26
|
+
let(:prod_A2) { Syntax::Production.new(nt_A, [b_]) }
|
27
|
+
let(:start_dotted_rule) { DottedItem.new(prod_S, 0) }
|
15
28
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
let(:prod_A2) { Syntax::Production.new(nt_A, [b_]) }
|
28
|
-
let(:start_dotted_rule) { DottedItem.new(prod_S, 0) }
|
29
|
-
|
30
|
-
# Helper method that mimicks the output of a tokenizer
|
31
|
-
# for the language specified by gramma_abc
|
32
|
-
let(:grm1_tokens) do
|
33
|
-
[
|
34
|
-
Token.new('a', a_),
|
35
|
-
Token.new('a', a_),
|
36
|
-
Token.new('b', b_),
|
37
|
-
Token.new('c', c_),
|
38
|
-
Token.new('c', c_)
|
39
|
-
]
|
40
|
-
end
|
29
|
+
# Helper method that mimicks the output of a tokenizer
|
30
|
+
# for the language specified by gramma_abc
|
31
|
+
let(:grm1_tokens) do
|
32
|
+
[
|
33
|
+
Token.new('a', a_),
|
34
|
+
Token.new('a', a_),
|
35
|
+
Token.new('b', b_),
|
36
|
+
Token.new('c', c_),
|
37
|
+
Token.new('c', c_)
|
38
|
+
]
|
39
|
+
end
|
41
40
|
|
42
|
-
|
43
|
-
|
41
|
+
# Default instantiation rule
|
42
|
+
subject { Parsing.new(start_dotted_rule, grm1_tokens) }
|
44
43
|
|
45
|
-
|
44
|
+
context 'Initialization:' do
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
it 'should be created with list of tokens and start dotted rule' do
|
47
|
+
start_rule = start_dotted_rule
|
48
|
+
tokens = grm1_tokens
|
49
|
+
expect { Parsing.new(start_rule, tokens) }.not_to raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should know the input tokens' do
|
53
|
+
expect(subject.tokens).to eq(grm1_tokens)
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
it 'should know its chart object' do
|
57
|
+
expect(subject.chart).to be_kind_of(Chart)
|
58
|
+
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
end # context
|
61
|
+
|
62
|
+
context 'Parsing:' do
|
63
|
+
it 'should push a state to a given chart entry' do
|
64
|
+
expect(subject.chart[1]).to be_empty
|
65
|
+
item = DottedItem.new(prod_A1, 1)
|
66
|
+
|
67
|
+
subject.push_state(item, 1, 1)
|
68
|
+
expect(subject.chart[1]).not_to be_empty
|
69
|
+
expect(subject.chart[1].first.dotted_rule).to eq(item)
|
70
|
+
|
71
|
+
# Pushing twice the same state must be no-op
|
72
|
+
subject.push_state(item, 1, 1)
|
73
|
+
expect(subject.chart[1].size).to eq(1)
|
74
|
+
end
|
65
75
|
|
66
|
-
|
67
|
-
|
68
|
-
|
76
|
+
it 'should complain when trying to push a nil dotted item' do
|
77
|
+
err = StandardError
|
78
|
+
msg = 'Dotted item may not be nil'
|
79
|
+
expect { subject.push_state(nil, 1, 1) }.to raise_error(err, msg)
|
80
|
+
end
|
69
81
|
|
70
|
-
# Pushing twice the same state must be no-op
|
71
|
-
subject.push_state(item, 1, 1)
|
72
|
-
expect(subject.chart[1].size).to eq(1)
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'should complain when trying to push a nil dotted item' do
|
76
|
-
err = StandardError
|
77
|
-
msg = 'Dotted item may not be nil'
|
78
|
-
expect { subject.push_state(nil, 1, 1) }.to raise_error(err, msg)
|
79
|
-
end
|
80
|
-
|
81
|
-
|
82
|
-
it 'should retrieve the parse states that expect a given terminal' do
|
83
|
-
item1 = DottedItem.new(prod_A1, 2)
|
84
|
-
item2 = DottedItem.new(prod_A1, 1)
|
85
|
-
subject.push_state(item1, 2, 2)
|
86
|
-
subject.push_state(item2, 2, 2)
|
87
|
-
states = subject.states_expecting(c_, 2)
|
88
|
-
expect(states.size).to eq(1)
|
89
|
-
expect(states[0].dotted_rule).to eq(item1)
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'should update the states upon token match' do
|
93
|
-
# When a input token matches an expected terminal symbol
|
94
|
-
# then new parse states must be pushed to the following chart slot
|
95
|
-
expect(subject.chart[1]).to be_empty
|
96
82
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
83
|
+
it 'should retrieve the parse states that expect a given terminal' do
|
84
|
+
item1 = DottedItem.new(prod_A1, 2)
|
85
|
+
item2 = DottedItem.new(prod_A1, 1)
|
86
|
+
subject.push_state(item1, 2, 2)
|
87
|
+
subject.push_state(item2, 2, 2)
|
88
|
+
states = subject.states_expecting(c_, 2)
|
89
|
+
expect(states.size).to eq(1)
|
90
|
+
expect(states[0].dotted_rule).to eq(item1)
|
91
|
+
end
|
102
92
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
93
|
+
it 'should update the states upon token match' do
|
94
|
+
# When a input token matches an expected terminal symbol
|
95
|
+
# then new parse states must be pushed to the following chart slot
|
96
|
+
expect(subject.chart[1]).to be_empty
|
97
|
+
|
98
|
+
item1 = DottedItem.new(prod_A1, 0)
|
99
|
+
item2 = DottedItem.new(prod_A2, 0)
|
100
|
+
subject.push_state(item1, 0, 0)
|
101
|
+
subject.push_state(item2, 0, 0)
|
102
|
+
subject.scanning(a_, 0) { |i| i } # Code block is mock
|
103
|
+
|
104
|
+
# Expected side effect: a new state at chart[1]
|
105
|
+
expect(subject.chart[1].size).to eq(1)
|
106
|
+
new_state = subject.chart[1].states[0]
|
107
|
+
expect(new_state.dotted_rule).to eq(item1)
|
108
|
+
expect(new_state.origin).to eq(0)
|
109
|
+
end
|
112
110
|
|
113
|
-
|
111
|
+
end
|
114
112
|
|
113
|
+
end # describe
|
115
114
|
end # module
|
116
115
|
end # module
|
117
116
|
|
118
|
-
# End of file
|
117
|
+
# End of file
|
@@ -7,62 +7,60 @@ require_relative '../../../lib/rley/parser/state_set'
|
|
7
7
|
|
8
8
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
9
9
|
module Parser # Open this namespace to avoid module qualifier prefixes
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end # describe
|
64
|
-
|
10
|
+
describe StateSet do
|
11
|
+
let(:dotted_rule1) { double('fake_dotted_rule1') }
|
12
|
+
let(:state1) { ParseState.new(dotted_rule1, 2) }
|
13
|
+
let(:dotted_rule2) { double('fake_dotted_rule2') }
|
14
|
+
let(:state2) { ParseState.new(dotted_rule2, 5) }
|
15
|
+
|
16
|
+
context 'Initialization:' do
|
17
|
+
|
18
|
+
it 'should be created without argument' do
|
19
|
+
expect { StateSet.new }.not_to raise_error
|
20
|
+
end
|
21
|
+
end # context
|
22
|
+
|
23
|
+
context 'Provided services:' do
|
24
|
+
|
25
|
+
it 'should push a state' do
|
26
|
+
expect(subject.states).to be_empty
|
27
|
+
expect { subject.push_state(state1) }.not_to raise_error
|
28
|
+
expect(subject).not_to be_empty
|
29
|
+
subject.push_state(state2)
|
30
|
+
expect(subject.states).to eq([state1, state2])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should list the states expecting a given terminal' do
|
34
|
+
# Case of no state
|
35
|
+
expect(subject.states_expecting(:a)).to be_empty
|
36
|
+
|
37
|
+
# Adding states
|
38
|
+
subject.push_state(state1)
|
39
|
+
subject.push_state(state2)
|
40
|
+
allow(dotted_rule1).to receive(:next_symbol).and_return(:b)
|
41
|
+
allow(dotted_rule2).to receive(:next_symbol).and_return(:a)
|
42
|
+
expect(subject.states_expecting(:a)).to eq([state2])
|
43
|
+
expect(subject.states_expecting(:b)).to eq([state1])
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should list the states related to a production' do
|
47
|
+
a_prod = double('fake-production')
|
48
|
+
|
49
|
+
# Case of no state
|
50
|
+
expect(subject.states_for(a_prod)).to be_empty
|
51
|
+
|
52
|
+
# Adding states
|
53
|
+
subject.push_state(state1)
|
54
|
+
subject.push_state(state2)
|
55
|
+
allow(dotted_rule1).to receive(:production).and_return(:dummy)
|
56
|
+
allow(dotted_rule2).to receive(:production).and_return(a_prod)
|
57
|
+
expect(subject.states_for(a_prod)).to eq([state2])
|
58
|
+
end
|
59
|
+
|
60
|
+
end # context
|
61
|
+
|
62
|
+
end # describe
|
65
63
|
end # module
|
66
64
|
end # module
|
67
65
|
|
68
|
-
# End of file
|
66
|
+
# End of file
|