rley 0.1.08 → 0.1.09
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/.rubocop.yml +81 -74
- data/CHANGELOG.md +4 -0
- data/Rakefile +4 -6
- data/examples/grammars/grammar_L0.rb +31 -31
- data/examples/grammars/grammar_abc.rb +26 -26
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/formatter/base_formatter.rb +1 -3
- data/lib/rley/formatter/debug.rb +1 -3
- data/lib/rley/formatter/json.rb +2 -5
- data/lib/rley/parse_tree_visitor.rb +0 -2
- data/lib/rley/parser/dotted_item.rb +3 -1
- data/lib/rley/parser/earley_parser.rb +4 -4
- data/lib/rley/parser/parsing.rb +10 -9
- data/lib/rley/parser/state_set.rb +1 -3
- data/lib/rley/ptree/non_terminal_node.rb +1 -1
- data/lib/rley/ptree/parse_tree.rb +32 -34
- data/lib/rley/ptree/parse_tree_node.rb +1 -3
- data/lib/rley/ptree/terminal_node.rb +1 -2
- data/lib/rley/ptree/token_range.rb +14 -14
- data/spec/rley/formatter/debug_spec.rb +65 -68
- data/spec/rley/formatter/json_spec.rb +69 -72
- data/spec/rley/parse_tree_visitor_spec.rb +5 -7
- data/spec/rley/parser/chart_spec.rb +0 -4
- data/spec/rley/parser/dotted_item_spec.rb +0 -3
- data/spec/rley/parser/earley_parser_spec.rb +0 -1
- data/spec/rley/parser/parse_state_spec.rb +0 -5
- data/spec/rley/parser/parsing_spec.rb +0 -3
- data/spec/rley/parser/state_set_spec.rb +0 -4
- data/spec/rley/parser/token_spec.rb +0 -4
- data/spec/rley/ptree/non_terminal_node_spec.rb +0 -1
- data/spec/rley/ptree/parse_tree_node_spec.rb +4 -4
- data/spec/rley/ptree/parse_tree_spec.rb +2 -3
- data/spec/rley/ptree/token_range_spec.rb +16 -17
- data/spec/rley/support/grammar_abc_helper.rb +0 -2
- data/spec/rley/syntax/grammar_builder_spec.rb +1 -4
- data/spec/rley/syntax/grammar_spec.rb +0 -9
- data/spec/rley/syntax/grm_symbol_spec.rb +0 -1
- data/spec/rley/syntax/literal_spec.rb +0 -1
- data/spec/rley/syntax/non_terminal_spec.rb +0 -1
- data/spec/rley/syntax/production_spec.rb +0 -2
- data/spec/rley/syntax/symbol_seq_spec.rb +0 -1
- data/spec/rley/syntax/terminal_spec.rb +0 -1
- data/spec/rley/syntax/verbatim_symbol_spec.rb +0 -1
- metadata +2 -2
data/lib/rley/parser/parsing.rb
CHANGED
@@ -45,7 +45,8 @@ module Rley # This module is used as a namespace
|
|
45
45
|
if ptree.current_node.is_a?(PTree::TerminalNode)
|
46
46
|
ptree.current_node.token = tokens[state_set_index]
|
47
47
|
end
|
48
|
-
|
48
|
+
state_set = chart[state_set_index]
|
49
|
+
parse_state = state_set.predecessor_state(parse_state)
|
49
50
|
curr_dotted_item = parse_state.dotted_rule
|
50
51
|
|
51
52
|
when Syntax::NonTerminal
|
@@ -58,8 +59,8 @@ module Rley # This module is used as a namespace
|
|
58
59
|
node_range = ptree.current_node.range
|
59
60
|
ptree.add_children(curr_dotted_item.production, node_range)
|
60
61
|
if ptree.current_node.is_a?(PTree::TerminalNode)
|
61
|
-
|
62
|
-
|
62
|
+
a_node = ptree.current_node
|
63
|
+
a_node.token = tokens[state_set_index - 1] unless a_node.token
|
63
64
|
end
|
64
65
|
|
65
66
|
when NilClass
|
@@ -102,12 +103,12 @@ module Rley # This module is used as a namespace
|
|
102
103
|
# determine the "next" dotted rule for a given one.
|
103
104
|
def scanning(aTerminal, aPosition, &nextMapping)
|
104
105
|
curr_token = tokens[aPosition]
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
106
|
+
return unless curr_token.terminal == aTerminal
|
107
|
+
|
108
|
+
states = states_expecting(aTerminal, aPosition)
|
109
|
+
states.each do |s|
|
110
|
+
next_item = nextMapping.call(s.dotted_rule)
|
111
|
+
push_state(next_item, s.origin, aPosition + 1)
|
111
112
|
end
|
112
113
|
end
|
113
114
|
|
@@ -42,15 +42,13 @@ module Rley # This module is used as a namespace
|
|
42
42
|
# Retrieve the parse state that is the predecessor of the given one.
|
43
43
|
def predecessor_state(aParseState)
|
44
44
|
if aParseState.dotted_rule.prev_position.nil?
|
45
|
-
|
45
|
+
fail StandardError, "#{aParseState}"
|
46
46
|
else
|
47
|
-
prod = aParseState.dotted_rule.production
|
48
47
|
candidate = states.find { |s| s.precedes?(aParseState) }
|
49
48
|
end
|
50
49
|
|
51
50
|
return candidate
|
52
51
|
end
|
53
|
-
|
54
52
|
|
55
53
|
private
|
56
54
|
|
@@ -38,9 +38,9 @@ module Rley # This module is used as a namespace
|
|
38
38
|
aProduction.rhs.each do |symb|
|
39
39
|
case symb
|
40
40
|
when Syntax::Terminal
|
41
|
-
new_node = TerminalNode.new(symb,{})
|
41
|
+
new_node = TerminalNode.new(symb, {})
|
42
42
|
when Syntax::NonTerminal
|
43
|
-
new_node = NonTerminalNode.new(symb,{})
|
43
|
+
new_node = NonTerminalNode.new(symb, {})
|
44
44
|
end
|
45
45
|
|
46
46
|
current_node.add_child(new_node)
|
@@ -49,57 +49,55 @@ module Rley # This module is used as a namespace
|
|
49
49
|
children = current_node.children
|
50
50
|
children.first.range = low_bound(aRange)
|
51
51
|
children.last.range = high_bound(aRange)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
return if children.empty?
|
53
|
+
|
54
|
+
path_increment = [children.size - 1, children.last]
|
55
|
+
@current_path.concat(path_increment)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
# Move the current node to the parent node.
|
59
59
|
# @param tokenPos [Fixnum] position of the matching input token
|
60
|
-
def step_up(
|
61
|
-
|
60
|
+
def step_up(_tokenPos)
|
61
|
+
current_path.pop(2)
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
|
65
65
|
|
66
66
|
# Move the current node to the previous sibling node.
|
67
67
|
# @param tokenPos [Fixnum] position of the matching input token
|
68
68
|
def step_back(tokenPos)
|
69
69
|
(pos, last_node) = current_path[-2, 2]
|
70
|
-
last_node.range = low_bound(
|
71
|
-
|
72
|
-
if pos
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
70
|
+
last_node.range = low_bound(low: tokenPos)
|
71
|
+
|
72
|
+
return if pos <= 0
|
73
|
+
current_path.pop(2)
|
74
|
+
new_pos = pos - 1
|
75
|
+
new_curr_node = current_path.last.children[new_pos]
|
76
|
+
current_path << new_pos
|
77
|
+
current_path << new_curr_node
|
78
|
+
new_curr_node.range = high_bound(high: tokenPos)
|
80
79
|
end
|
81
80
|
|
82
81
|
private
|
83
82
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
return { low: result }
|
83
|
+
def low_bound(aRange)
|
84
|
+
result = case aRange
|
85
|
+
when Hash then aRange[:low]
|
86
|
+
when TokenRange then aRange.low
|
91
87
|
end
|
92
88
|
|
93
|
-
|
94
|
-
|
95
|
-
when Hash then aRange[:high]
|
96
|
-
when TokenRange then aRange.high
|
97
|
-
end
|
89
|
+
return { low: result }
|
90
|
+
end
|
98
91
|
|
99
|
-
|
92
|
+
def high_bound(aRange)
|
93
|
+
result = case aRange
|
94
|
+
when Hash then aRange[:high]
|
95
|
+
when TokenRange then aRange.high
|
100
96
|
end
|
101
97
|
|
98
|
+
return { high: result }
|
99
|
+
end
|
102
100
|
end # class
|
103
101
|
end # module
|
104
102
|
end # module
|
105
|
-
# End of file
|
103
|
+
# End of file
|
@@ -9,7 +9,6 @@ module Rley # This module is used as a namespace
|
|
9
9
|
# A range of indices for tokens corresponding to the node.
|
10
10
|
attr_reader(:range)
|
11
11
|
|
12
|
-
|
13
12
|
def initialize(aSymbol, aRange)
|
14
13
|
@symbol = aSymbol
|
15
14
|
@range = TokenRange.new(aRange)
|
@@ -18,8 +17,7 @@ module Rley # This module is used as a namespace
|
|
18
17
|
def range=(aRange)
|
19
18
|
range.assign(aRange)
|
20
19
|
end
|
21
|
-
|
22
20
|
end # class
|
23
21
|
end # module
|
24
22
|
end # module
|
25
|
-
# End of file
|
23
|
+
# End of file
|
@@ -12,18 +12,18 @@ module Rley # This module is used as a namespace
|
|
12
12
|
assign_low(aRangeRep)
|
13
13
|
assign_high(aRangeRep)
|
14
14
|
end
|
15
|
-
|
16
|
-
|
15
|
+
|
16
|
+
|
17
17
|
def ==(other)
|
18
18
|
return true if object_id == other.object_id
|
19
|
-
|
19
|
+
|
20
20
|
case other
|
21
21
|
when Hash
|
22
22
|
result = low == other[:low] && high == other[:high]
|
23
23
|
when TokenRange
|
24
24
|
result = low == other.low && high == other.high
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
return result
|
28
28
|
end
|
29
29
|
|
@@ -31,31 +31,31 @@ module Rley # This module is used as a namespace
|
|
31
31
|
def bounded?()
|
32
32
|
return !(low.nil? || high.nil?)
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
# Conditional assign
|
36
36
|
def assign(aRange)
|
37
37
|
return if bounded?
|
38
|
-
|
38
|
+
|
39
39
|
assign_low(aRange) if low.nil?
|
40
40
|
assign_high(aRange) if high.nil?
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
private
|
44
|
+
|
44
45
|
def assign_low(aRange)
|
45
46
|
case aRange
|
46
|
-
|
47
|
-
|
47
|
+
when Hash then @low = aRange.fetch(:low, nil)
|
48
|
+
when TokenRange then @low = aRange.low
|
48
49
|
end
|
49
50
|
end
|
50
|
-
|
51
|
+
|
51
52
|
def assign_high(aRange)
|
52
53
|
case aRange
|
53
|
-
|
54
|
-
|
54
|
+
when Hash then @high = aRange.fetch(:high, nil)
|
55
|
+
when TokenRange then @high = aRange.high
|
55
56
|
end
|
56
57
|
end
|
57
|
-
|
58
58
|
end # class
|
59
59
|
end # module
|
60
60
|
end # module
|
61
|
-
# End of file
|
61
|
+
# End of file
|
@@ -10,75 +10,73 @@ require_relative '../../../lib/rley/parse_tree_visitor'
|
|
10
10
|
require_relative '../../../lib/rley/formatter/debug'
|
11
11
|
|
12
12
|
module Rley # Re-open the module to get rid of qualified names
|
13
|
-
module Formatter
|
13
|
+
module Formatter
|
14
|
+
describe Debug do
|
15
|
+
include GrammarABCHelper # Mix-in module for grammar abc
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
+
# Factory method. Build a production with the given sequence
|
18
|
+
# of symbols as its rhs.
|
19
|
+
let(:grammar_abc) do
|
20
|
+
builder = grammar_abc_builder
|
21
|
+
builder.grammar
|
22
|
+
end
|
23
|
+
|
24
|
+
# Variables for the terminal symbols
|
25
|
+
let(:a_) { grammar_abc.name2symbol['a'] }
|
26
|
+
let(:b_) { grammar_abc.name2symbol['b'] }
|
27
|
+
let(:c_) { grammar_abc.name2symbol['c'] }
|
28
|
+
|
29
|
+
# Helper method that mimicks the output of a tokenizer
|
30
|
+
# for the language specified by gramma_abc
|
31
|
+
let(:grm_abc_tokens1) do
|
32
|
+
[
|
33
|
+
Parser::Token.new('a', a_),
|
34
|
+
Parser::Token.new('a', a_),
|
35
|
+
Parser::Token.new('b', b_),
|
36
|
+
Parser::Token.new('c', c_),
|
37
|
+
Parser::Token.new('c', c_)
|
38
|
+
]
|
39
|
+
end
|
17
40
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
Parser::Token.new('a', a_),
|
36
|
-
Parser::Token.new('b', b_),
|
37
|
-
Parser::Token.new('c', c_),
|
38
|
-
Parser::Token.new('c', c_)
|
39
|
-
]
|
40
|
-
end
|
41
|
-
|
42
|
-
# Factory method that builds a sample parse tree.
|
43
|
-
# Generated tree has the following structure:
|
44
|
-
# S[0,5]
|
45
|
-
# +- A[0,5]
|
46
|
-
# +- a[0,0]
|
47
|
-
# +- A[1,4]
|
48
|
-
# | +- a[1,1]
|
49
|
-
# | +- A[2,3]
|
50
|
-
# | | +- b[2,3]
|
51
|
-
# | +- c[3,4]
|
52
|
-
# +- c[4,5]
|
53
|
-
# Capital letters represent non-terminal nodes
|
54
|
-
let(:grm_abc_ptree1) do
|
55
|
-
parser = Parser::EarleyParser.new(grammar_abc)
|
56
|
-
parse_result = parser.parse(grm_abc_tokens1)
|
57
|
-
parse_result.parse_tree
|
58
|
-
end
|
41
|
+
# Factory method that builds a sample parse tree.
|
42
|
+
# Generated tree has the following structure:
|
43
|
+
# S[0,5]
|
44
|
+
# +- A[0,5]
|
45
|
+
# +- a[0,0]
|
46
|
+
# +- A[1,4]
|
47
|
+
# | +- a[1,1]
|
48
|
+
# | +- A[2,3]
|
49
|
+
# | | +- b[2,3]
|
50
|
+
# | +- c[3,4]
|
51
|
+
# +- c[4,5]
|
52
|
+
# Capital letters represent non-terminal nodes
|
53
|
+
let(:grm_abc_ptree1) do
|
54
|
+
parser = Parser::EarleyParser.new(grammar_abc)
|
55
|
+
parse_result = parser.parse(grm_abc_tokens1)
|
56
|
+
parse_result.parse_tree
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
context 'Standard creation & initialization:' do
|
59
|
+
let(:destination) { StringIO.new('', 'w') }
|
63
60
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
61
|
+
context 'Standard creation & initialization:' do
|
62
|
+
it 'should be initialized with an IO argument' do
|
63
|
+
expect { Debug.new(StringIO.new('', 'w')) }.not_to raise_error
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should know its output destination' do
|
67
|
+
instance = Debug.new(destination)
|
68
|
+
expect(instance.output).to eq(destination)
|
69
|
+
end
|
70
|
+
end # context
|
73
71
|
|
74
72
|
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
74
|
+
context 'Formatting events:' do
|
75
|
+
it 'should support visit events of a parse tree' do
|
76
|
+
instance = Debug.new(destination)
|
77
|
+
visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
|
78
|
+
instance.render(visitor)
|
79
|
+
expectations = <<-SNIPPET
|
82
80
|
before_ptree
|
83
81
|
before_non_terminal
|
84
82
|
before_children
|
@@ -108,12 +106,11 @@ before_ptree
|
|
108
106
|
after_non_terminal
|
109
107
|
after_ptree
|
110
108
|
SNIPPET
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end # describe
|
115
|
-
|
116
|
-
end # module
|
109
|
+
expect(destination.string).to eq(expectations)
|
110
|
+
end
|
111
|
+
end # context
|
112
|
+
end # describe
|
113
|
+
end # module
|
117
114
|
end # module
|
118
115
|
|
119
116
|
# End of file
|
@@ -11,75 +11,73 @@ require_relative '../../../lib/rley/parse_tree_visitor'
|
|
11
11
|
require_relative '../../../lib/rley/formatter/json'
|
12
12
|
|
13
13
|
module Rley # Re-open the module to get rid of qualified names
|
14
|
-
module Formatter
|
14
|
+
module Formatter
|
15
|
+
describe Json do
|
16
|
+
include GrammarABCHelper # Mix-in module with builder for grammar abc
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
Parser::Token.new('c', c_)
|
40
|
-
]
|
41
|
-
end
|
42
|
-
|
43
|
-
# Factory method that builds a sample parse tree.
|
44
|
-
# Generated tree has the following structure:
|
45
|
-
# S[0,5]
|
46
|
-
# +- A[0,5]
|
47
|
-
# +- a[0,0]
|
48
|
-
# +- A[1,4]
|
49
|
-
# | +- a[1,1]
|
50
|
-
# | +- A[2,3]
|
51
|
-
# | | +- b[2,3]
|
52
|
-
# | +- c[3,4]
|
53
|
-
# +- c[4,5]
|
54
|
-
# Capital letters represent non-terminal nodes
|
55
|
-
let(:grm_abc_ptree1) do
|
56
|
-
parser = Parser::EarleyParser.new(grammar_abc)
|
57
|
-
parse_result = parser.parse(grm_abc_tokens1)
|
58
|
-
parse_result.parse_tree
|
59
|
-
end
|
60
|
-
|
61
|
-
let(:destination) { StringIO.new('', 'w') }
|
18
|
+
# Factory method. Build a production with the given sequence
|
19
|
+
# of symbols as its rhs.
|
20
|
+
let(:grammar_abc) do
|
21
|
+
builder = grammar_abc_builder
|
22
|
+
builder.grammar
|
23
|
+
end
|
24
|
+
|
25
|
+
# Variables for the terminal symbols
|
26
|
+
let(:a_) { grammar_abc.name2symbol['a'] }
|
27
|
+
let(:b_) { grammar_abc.name2symbol['b'] }
|
28
|
+
let(:c_) { grammar_abc.name2symbol['c'] }
|
29
|
+
|
30
|
+
# Helper method that mimicks the output of a tokenizer
|
31
|
+
# for the language specified by gramma_abc
|
32
|
+
let(:grm_abc_tokens1) do
|
33
|
+
[
|
34
|
+
Parser::Token.new('a', a_),
|
35
|
+
Parser::Token.new('a', a_),
|
36
|
+
Parser::Token.new('b', b_),
|
37
|
+
Parser::Token.new('c', c_),
|
38
|
+
Parser::Token.new('c', c_)
|
39
|
+
]
|
40
|
+
end
|
62
41
|
|
63
|
-
|
42
|
+
# Factory method that builds a sample parse tree.
|
43
|
+
# Generated tree has the following structure:
|
44
|
+
# S[0,5]
|
45
|
+
# +- A[0,5]
|
46
|
+
# +- a[0,0]
|
47
|
+
# +- A[1,4]
|
48
|
+
# | +- a[1,1]
|
49
|
+
# | +- A[2,3]
|
50
|
+
# | | +- b[2,3]
|
51
|
+
# | +- c[3,4]
|
52
|
+
# +- c[4,5]
|
53
|
+
# Capital letters represent non-terminal nodes
|
54
|
+
let(:grm_abc_ptree1) do
|
55
|
+
parser = Parser::EarleyParser.new(grammar_abc)
|
56
|
+
parse_result = parser.parse(grm_abc_tokens1)
|
57
|
+
parse_result.parse_tree
|
58
|
+
end
|
59
|
+
|
60
|
+
let(:destination) { StringIO.new('', 'w') }
|
64
61
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
62
|
+
context 'Standard creation & initialization:' do
|
63
|
+
it 'should be initialized with an IO argument' do
|
64
|
+
expect { Json.new(StringIO.new('', 'w')) }.not_to raise_error
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should know its output destination' do
|
68
|
+
instance = Json.new(destination)
|
69
|
+
expect(instance.output).to eq(destination)
|
70
|
+
end
|
71
|
+
end # context
|
72
|
+
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
74
|
+
|
75
|
+
context 'Formatting events:' do
|
76
|
+
it 'should render a parse tree in JSON' do
|
77
|
+
instance = Json.new(destination)
|
78
|
+
visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
|
79
|
+
instance.render(visitor)
|
80
|
+
expectations = <<-SNIPPET
|
83
81
|
{
|
84
82
|
"root":
|
85
83
|
{ "S": [
|
@@ -100,13 +98,12 @@ describe Json do
|
|
100
98
|
]
|
101
99
|
}
|
102
100
|
}
|
103
|
-
SNIPPET
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end # describe
|
108
|
-
|
109
|
-
end # module
|
101
|
+
SNIPPET
|
102
|
+
expect(destination.string).to eq(expectations.chomp)
|
103
|
+
end
|
104
|
+
end # context
|
105
|
+
end # describe
|
106
|
+
end # module
|
110
107
|
end # module
|
111
108
|
|
112
109
|
# End of file
|