rley 0.0.04 → 0.0.05
Sign up to get free protection for your applications and to get access to all the features.
- 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
|