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