rley 0.7.06 → 0.8.01
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 +362 -62
- data/.travis.yml +6 -6
- data/CHANGELOG.md +20 -4
- data/LICENSE.txt +1 -1
- data/README.md +7 -7
- data/examples/NLP/engtagger.rb +193 -190
- data/examples/NLP/nano_eng/nano_en_demo.rb +7 -11
- data/examples/NLP/nano_eng/nano_grammar.rb +21 -21
- data/examples/NLP/pico_en_demo.rb +2 -2
- data/examples/data_formats/JSON/cli_options.rb +1 -1
- data/examples/data_formats/JSON/json_ast_builder.rb +21 -27
- data/examples/data_formats/JSON/json_ast_nodes.rb +12 -21
- data/examples/data_formats/JSON/json_demo.rb +1 -2
- data/examples/data_formats/JSON/json_grammar.rb +13 -13
- data/examples/data_formats/JSON/json_lexer.rb +8 -8
- data/examples/data_formats/JSON/json_minifier.rb +1 -1
- data/examples/general/calc_iter1/calc_ast_builder.rb +13 -10
- data/examples/general/calc_iter1/calc_ast_nodes.rb +23 -37
- data/examples/general/calc_iter1/calc_grammar.rb +7 -6
- data/examples/general/calc_iter1/calc_lexer.rb +6 -4
- data/examples/general/calc_iter1/spec/calculator_spec.rb +5 -5
- data/examples/general/calc_iter2/calc_ast_builder.rb +5 -3
- data/examples/general/calc_iter2/calc_ast_nodes.rb +27 -43
- data/examples/general/calc_iter2/calc_grammar.rb +12 -12
- data/examples/general/calc_iter2/calc_lexer.rb +11 -10
- data/examples/general/calc_iter2/spec/calculator_spec.rb +26 -26
- data/examples/general/left.rb +2 -2
- data/examples/general/right.rb +2 -2
- data/lib/rley.rb +1 -1
- data/lib/rley/base/dotted_item.rb +28 -31
- data/lib/rley/base/grm_items_builder.rb +6 -0
- data/lib/rley/constants.rb +2 -2
- data/lib/rley/engine.rb +22 -25
- data/lib/rley/formatter/asciitree.rb +3 -3
- data/lib/rley/formatter/bracket_notation.rb +1 -8
- data/lib/rley/formatter/debug.rb +6 -6
- data/lib/rley/formatter/json.rb +2 -2
- data/lib/rley/gfg/call_edge.rb +1 -1
- data/lib/rley/gfg/edge.rb +5 -5
- data/lib/rley/gfg/end_vertex.rb +2 -6
- data/lib/rley/gfg/epsilon_edge.rb +1 -5
- data/lib/rley/gfg/grm_flow_graph.rb +27 -23
- data/lib/rley/gfg/item_vertex.rb +10 -10
- data/lib/rley/gfg/non_terminal_vertex.rb +4 -4
- data/lib/rley/gfg/scan_edge.rb +1 -1
- data/lib/rley/gfg/shortcut_edge.rb +2 -2
- data/lib/rley/gfg/start_vertex.rb +4 -8
- data/lib/rley/gfg/vertex.rb +43 -39
- data/lib/rley/interface.rb +16 -0
- data/lib/rley/lexical/token_range.rb +6 -6
- data/lib/rley/notation/all_notation_nodes.rb +2 -0
- data/lib/rley/notation/ast_builder.rb +191 -0
- data/lib/rley/notation/ast_node.rb +44 -0
- data/lib/rley/notation/ast_visitor.rb +113 -0
- data/lib/rley/notation/grammar.rb +49 -0
- data/lib/rley/notation/grammar_builder.rb +504 -0
- data/lib/rley/notation/grouping_node.rb +23 -0
- data/lib/rley/notation/parser.rb +56 -0
- data/lib/rley/notation/sequence_node.rb +35 -0
- data/lib/rley/notation/symbol_node.rb +29 -0
- data/lib/rley/notation/tokenizer.rb +192 -0
- data/lib/rley/parse_forest_visitor.rb +5 -5
- data/lib/rley/parse_rep/ast_base_builder.rb +48 -11
- data/lib/rley/parse_rep/cst_builder.rb +5 -6
- data/lib/rley/parse_rep/parse_forest_builder.rb +22 -18
- data/lib/rley/parse_rep/parse_forest_factory.rb +3 -3
- data/lib/rley/parse_rep/parse_rep_creator.rb +14 -16
- data/lib/rley/parse_rep/parse_tree_builder.rb +4 -4
- data/lib/rley/parse_rep/parse_tree_factory.rb +27 -27
- data/lib/rley/parse_tree_visitor.rb +1 -1
- data/lib/rley/parser/error_reason.rb +4 -5
- data/lib/rley/parser/gfg_chart.rb +118 -26
- data/lib/rley/parser/gfg_parsing.rb +22 -33
- data/lib/rley/parser/parse_entry.rb +25 -31
- data/lib/rley/parser/parse_entry_set.rb +19 -16
- data/lib/rley/parser/parse_entry_tracker.rb +4 -4
- data/lib/rley/parser/parse_tracer.rb +13 -13
- data/lib/rley/parser/parse_walker_factory.rb +23 -28
- data/lib/rley/ptree/non_terminal_node.rb +7 -5
- data/lib/rley/ptree/parse_tree.rb +3 -3
- data/lib/rley/ptree/parse_tree_node.rb +5 -5
- data/lib/rley/ptree/terminal_node.rb +7 -7
- data/lib/rley/rley_error.rb +12 -12
- data/lib/rley/sppf/alternative_node.rb +6 -6
- data/lib/rley/sppf/composite_node.rb +7 -7
- data/lib/rley/sppf/epsilon_node.rb +3 -3
- data/lib/rley/sppf/leaf_node.rb +3 -3
- data/lib/rley/sppf/parse_forest.rb +16 -16
- data/lib/rley/sppf/sppf_node.rb +7 -8
- data/lib/rley/sppf/token_node.rb +3 -3
- data/lib/rley/syntax/{grammar_builder.rb → base_grammar_builder.rb} +61 -23
- data/lib/rley/syntax/grammar.rb +5 -5
- data/lib/rley/syntax/grm_symbol.rb +7 -7
- data/lib/rley/syntax/match_closest.rb +43 -0
- data/lib/rley/syntax/non_terminal.rb +9 -15
- data/lib/rley/syntax/production.rb +16 -10
- data/lib/rley/syntax/symbol_seq.rb +7 -9
- data/lib/rley/syntax/terminal.rb +4 -5
- data/lib/rley/syntax/verbatim_symbol.rb +3 -3
- data/lib/support/base_tokenizer.rb +19 -18
- data/spec/rley/base/dotted_item_spec.rb +2 -2
- data/spec/rley/engine_spec.rb +23 -21
- data/spec/rley/formatter/asciitree_spec.rb +7 -7
- data/spec/rley/formatter/bracket_notation_spec.rb +13 -13
- data/spec/rley/formatter/json_spec.rb +1 -1
- data/spec/rley/gfg/end_vertex_spec.rb +5 -5
- data/spec/rley/gfg/grm_flow_graph_spec.rb +2 -2
- data/spec/rley/gfg/item_vertex_spec.rb +10 -10
- data/spec/rley/gfg/non_terminal_vertex_spec.rb +3 -3
- data/spec/rley/gfg/shortcut_edge_spec.rb +1 -1
- data/spec/rley/gfg/start_vertex_spec.rb +5 -5
- data/spec/rley/gfg/vertex_spec.rb +3 -3
- data/spec/rley/lexical/token_range_spec.rb +16 -16
- data/spec/rley/lexical/token_spec.rb +2 -2
- data/spec/rley/notation/grammar_builder_spec.rb +302 -0
- data/spec/rley/notation/parser_spec.rb +184 -0
- data/spec/rley/notation/tokenizer_spec.rb +370 -0
- data/spec/rley/parse_forest_visitor_spec.rb +165 -163
- data/spec/rley/parse_rep/ambiguous_parse_spec.rb +44 -44
- data/spec/rley/parse_rep/ast_builder_spec.rb +6 -7
- data/spec/rley/parse_rep/cst_builder_spec.rb +5 -5
- data/spec/rley/parse_rep/groucho_spec.rb +24 -26
- data/spec/rley/parse_rep/parse_forest_builder_spec.rb +27 -27
- data/spec/rley/parse_rep/parse_forest_factory_spec.rb +8 -8
- data/spec/rley/parse_rep/parse_tree_factory_spec.rb +3 -3
- data/spec/rley/parse_tree_visitor_spec.rb +10 -8
- data/spec/rley/parser/dangling_else_spec.rb +445 -0
- data/spec/rley/parser/error_reason_spec.rb +6 -6
- data/spec/rley/parser/gfg_earley_parser_spec.rb +120 -12
- data/spec/rley/parser/gfg_parsing_spec.rb +6 -13
- data/spec/rley/parser/parse_entry_spec.rb +19 -19
- data/spec/rley/parser/parse_walker_factory_spec.rb +10 -10
- data/spec/rley/ptree/non_terminal_node_spec.rb +5 -3
- data/spec/rley/ptree/parse_tree_node_spec.rb +4 -4
- data/spec/rley/ptree/terminal_node_spec.rb +6 -6
- data/spec/rley/sppf/alternative_node_spec.rb +6 -6
- data/spec/rley/sppf/non_terminal_node_spec.rb +3 -3
- data/spec/rley/sppf/token_node_spec.rb +4 -4
- data/spec/rley/support/ambiguous_grammar_helper.rb +4 -5
- data/spec/rley/support/grammar_abc_helper.rb +3 -5
- data/spec/rley/support/grammar_ambig01_helper.rb +5 -6
- data/spec/rley/support/grammar_arr_int_helper.rb +5 -6
- data/spec/rley/support/grammar_b_expr_helper.rb +5 -6
- data/spec/rley/support/grammar_int_seq_helper.rb +51 -0
- data/spec/rley/support/grammar_l0_helper.rb +14 -17
- data/spec/rley/support/grammar_pb_helper.rb +8 -7
- data/spec/rley/support/grammar_sppf_helper.rb +3 -3
- data/spec/rley/syntax/{grammar_builder_spec.rb → base_grammar_builder_spec.rb} +35 -16
- data/spec/rley/syntax/grammar_spec.rb +6 -6
- data/spec/rley/syntax/grm_symbol_spec.rb +1 -1
- data/spec/rley/syntax/match_closest_spec.rb +46 -0
- data/spec/rley/syntax/non_terminal_spec.rb +8 -8
- data/spec/rley/syntax/production_spec.rb +17 -13
- data/spec/rley/syntax/symbol_seq_spec.rb +2 -2
- data/spec/rley/syntax/terminal_spec.rb +5 -5
- data/spec/rley/syntax/verbatim_symbol_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -12
- data/spec/support/base_tokenizer_spec.rb +7 -2
- metadata +48 -74
- data/.simplecov +0 -7
- data/lib/rley/parser/parse_state.rb +0 -83
- data/lib/rley/parser/parse_state_tracker.rb +0 -59
- data/lib/rley/parser/state_set.rb +0 -101
- data/spec/rley/parser/parse_state_spec.rb +0 -125
- data/spec/rley/parser/parse_tracer_spec.rb +0 -200
- data/spec/rley/parser/state_set_spec.rb +0 -130
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Rley # This module is used as a namespace
|
4
|
-
module Parser # This module is used as a namespace
|
5
|
-
# Helper class that keeps track of the parse states used
|
6
|
-
# while a Parsing instance is constructing a parse tree.
|
7
|
-
class ParseStateTracker
|
8
|
-
# The index of the current state set
|
9
|
-
attr_reader(:state_set_index)
|
10
|
-
|
11
|
-
# The current parse state
|
12
|
-
attr_reader(:parse_state)
|
13
|
-
|
14
|
-
# The already processed states from current state set
|
15
|
-
attr_reader(:processed_states)
|
16
|
-
|
17
|
-
# Constructor. Refined variant of the inherited constructor.
|
18
|
-
def initialize(aStateSetIndex)
|
19
|
-
self.state_set_index = aStateSetIndex
|
20
|
-
end
|
21
|
-
|
22
|
-
# Write accessor. Sets the value of the state set index
|
23
|
-
def state_set_index=(anIndex)
|
24
|
-
@state_set_index = anIndex
|
25
|
-
@processed_states = {}
|
26
|
-
end
|
27
|
-
|
28
|
-
# Write accessor. Set the given parse state as the current one.
|
29
|
-
def parse_state=(aParseState)
|
30
|
-
raise StandardError, 'Nil parse state' if aParseState.nil?
|
31
|
-
|
32
|
-
@parse_state = aParseState
|
33
|
-
processed_states[parse_state] = true
|
34
|
-
end
|
35
|
-
|
36
|
-
# Take the first provided state that wasn't processed yet.
|
37
|
-
def select_state(theStates)
|
38
|
-
a_state = theStates.find { |st| !processed_states.include?(st) }
|
39
|
-
self.parse_state = a_state
|
40
|
-
end
|
41
|
-
|
42
|
-
# The dotted item for the current parse state.
|
43
|
-
def curr_dotted_item()
|
44
|
-
parse_state.dotted_rule
|
45
|
-
end
|
46
|
-
|
47
|
-
def symbol_on_left()
|
48
|
-
return curr_dotted_item.prev_symbol
|
49
|
-
end
|
50
|
-
|
51
|
-
# Notification that one begins with the previous state set
|
52
|
-
def to_prev_state_set()
|
53
|
-
self.state_set_index = state_set_index - 1
|
54
|
-
end
|
55
|
-
end # class
|
56
|
-
end # module
|
57
|
-
end # module
|
58
|
-
|
59
|
-
# End of file
|
@@ -1,101 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'forwardable' # Delegation
|
4
|
-
|
5
|
-
module Rley # This module is used as a namespace
|
6
|
-
module Parser # This module is used as a namespace
|
7
|
-
class StateSet
|
8
|
-
extend Forwardable
|
9
|
-
def_delegators :states, :empty?, :size, :first, :each
|
10
|
-
|
11
|
-
# The set of parse states
|
12
|
-
attr_reader(:states)
|
13
|
-
|
14
|
-
def initialize()
|
15
|
-
@states = []
|
16
|
-
end
|
17
|
-
|
18
|
-
# Append the given state (if it isn't yet in the set)
|
19
|
-
# to the list of states
|
20
|
-
# @param aState [ParseState] the state to push.
|
21
|
-
# @return [TrueClass/FalseClass] true when the state is really added
|
22
|
-
def push_state(aState)
|
23
|
-
if include?(aState)
|
24
|
-
result = false
|
25
|
-
else
|
26
|
-
@states << aState
|
27
|
-
result = true
|
28
|
-
end
|
29
|
-
|
30
|
-
return result
|
31
|
-
end
|
32
|
-
|
33
|
-
# The list of ParseState that expect the given symbol.
|
34
|
-
# @param aSymbol [GrmSymbol] the expected symbol
|
35
|
-
# (=on the right of the dot)
|
36
|
-
def states_expecting(aSymbol)
|
37
|
-
return states.select { |s| s.dotted_rule.next_symbol == aSymbol }
|
38
|
-
end
|
39
|
-
|
40
|
-
# The list of complete ParseState that have the given non-terminal
|
41
|
-
# symbol as the lhs of their production.
|
42
|
-
def states_rewriting(aNonTerm)
|
43
|
-
return states.select do |s|
|
44
|
-
(s.dotted_rule.production.lhs == aNonTerm) && s.complete?
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# The list of ParseState that involve the given production
|
49
|
-
def states_for(aProduction)
|
50
|
-
return states.select { |s| s.dotted_rule.production == aProduction }
|
51
|
-
end
|
52
|
-
|
53
|
-
# Retrieve the parse state that is the predecessor of the given one.
|
54
|
-
def predecessor_state(aPState)
|
55
|
-
dotted_rule = aPState.dotted_rule
|
56
|
-
raise StandardError, aPState.to_s unless dotted_rule.prev_position
|
57
|
-
|
58
|
-
candidate = states.find { |s| s.precedes?(aPState) }
|
59
|
-
return candidate
|
60
|
-
end
|
61
|
-
|
62
|
-
# The list of distinct expected terminal symbols. An expected symbol
|
63
|
-
# is on the left of a dot in a parse state of the parse set.
|
64
|
-
def expected_terminals()
|
65
|
-
expecting_terminals = states.select do |s|
|
66
|
-
s.dotted_rule.next_symbol.kind_of?(Rley::Syntax::Terminal)
|
67
|
-
end
|
68
|
-
|
69
|
-
terminals = expecting_terminals.map { |s| s.dotted_rule.next_symbol }
|
70
|
-
return terminals.uniq
|
71
|
-
end
|
72
|
-
|
73
|
-
# Return an Array of Arrays of ambiguous parse states.
|
74
|
-
def ambiguities()
|
75
|
-
complete_states = states.select(&:complete?)
|
76
|
-
return [] if complete_states.size <= 1
|
77
|
-
|
78
|
-
# Group parse state by lhs symbol and origin
|
79
|
-
groupings = complete_states.group_by do |st|
|
80
|
-
st.dotted_rule.lhs.object_id.to_s
|
81
|
-
end
|
82
|
-
|
83
|
-
# Retain the groups having more than one element.
|
84
|
-
ambiguous_groups = []
|
85
|
-
groupings.each_value do |a_group|
|
86
|
-
ambiguous_groups << a_group if a_group.size > 1
|
87
|
-
end
|
88
|
-
|
89
|
-
return ambiguous_groups
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
def include?(aState)
|
95
|
-
# TODO: make it better than linear search
|
96
|
-
return states.include?(aState)
|
97
|
-
end
|
98
|
-
end # class
|
99
|
-
end # module
|
100
|
-
end # module
|
101
|
-
# End of file
|
@@ -1,125 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../../spec_helper'
|
4
|
-
|
5
|
-
require_relative '../../../lib/rley/syntax/terminal'
|
6
|
-
require_relative '../../../lib/rley/syntax/non_terminal'
|
7
|
-
require_relative '../../../lib/rley/syntax/production'
|
8
|
-
require_relative '../../../lib/rley/base/dotted_item'
|
9
|
-
|
10
|
-
# Load the class under test
|
11
|
-
require_relative '../../../lib/rley/parser/parse_state'
|
12
|
-
|
13
|
-
module Rley # Open this namespace to avoid module qualifier prefixes
|
14
|
-
module Parser # Open this namespace to avoid module qualifier prefixes
|
15
|
-
describe ParseState do
|
16
|
-
let(:t_a) { Syntax::Terminal.new('A') }
|
17
|
-
let(:t_b) { Syntax::Terminal.new('B') }
|
18
|
-
let(:t_c) { Syntax::Terminal.new('C') }
|
19
|
-
let(:nt_sentence) { Syntax::NonTerminal.new('sentence') }
|
20
|
-
|
21
|
-
let(:sample_prod) do
|
22
|
-
Syntax::Production.new(nt_sentence, [t_a, t_b, t_c])
|
23
|
-
end
|
24
|
-
|
25
|
-
let(:other_prod) do
|
26
|
-
Syntax::Production.new(nt_sentence, [t_a])
|
27
|
-
end
|
28
|
-
|
29
|
-
let(:empty_prod) do
|
30
|
-
Syntax::Production.new(nt_sentence, [])
|
31
|
-
end
|
32
|
-
|
33
|
-
let(:origin_val) { 3 }
|
34
|
-
let(:dotted_rule) { Base::DottedItem.new(sample_prod, 2) }
|
35
|
-
let(:other_dotted_rule) { double('mock-dotted-item') }
|
36
|
-
|
37
|
-
# Default instantiation rule
|
38
|
-
subject { ParseState.new(dotted_rule, origin_val) }
|
39
|
-
|
40
|
-
context 'Initialization:' do
|
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
|
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
|
51
|
-
|
52
|
-
it 'should know the related dotted rule' do
|
53
|
-
expect(subject.dotted_rule).to eq(dotted_rule)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'should know the origin value' do
|
57
|
-
expect(subject.origin).to eq(origin_val)
|
58
|
-
end
|
59
|
-
end # context
|
60
|
-
|
61
|
-
context 'Provided services:' do
|
62
|
-
def new_parse_state(aProd, aRank, aVal)
|
63
|
-
item = Base::DottedItem.new(aProd, aRank)
|
64
|
-
ParseState.new(item, aVal)
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'should compare with itself' do
|
68
|
-
synonym = subject # Fool Rubocop
|
69
|
-
expect(subject == synonym).to eq(true)
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'should compare with another' do
|
73
|
-
equal = ParseState.new(dotted_rule, origin_val)
|
74
|
-
expect(subject == equal).to eq(true)
|
75
|
-
|
76
|
-
# Same dotted_rule, different origin
|
77
|
-
diff_origin = ParseState.new(dotted_rule, 2)
|
78
|
-
expect(subject == diff_origin).to eq(false)
|
79
|
-
|
80
|
-
# Different dotted item, same origin
|
81
|
-
diff_rule = ParseState.new(other_dotted_rule, 3)
|
82
|
-
expect(subject == diff_rule).to eq(false)
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'should know if the parsing is at the start of the production' do
|
86
|
-
expect(subject).not_to be_predicted
|
87
|
-
at_start = Base::DottedItem.new(sample_prod, 0)
|
88
|
-
|
89
|
-
instance = ParseState.new(at_start, 0)
|
90
|
-
expect(instance).to be_predicted
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'should know if the parsing reached the end of the production' do
|
94
|
-
expect(subject).not_to be_complete
|
95
|
-
at_end = Base::DottedItem.new(sample_prod, 3)
|
96
|
-
|
97
|
-
instance = ParseState.new(at_end, 2)
|
98
|
-
expect(instance).to be_complete
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'should know the next expected symbol' do
|
102
|
-
expect(subject.next_symbol).to eq(t_c)
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'should know whether another instance follows this one' do
|
106
|
-
expect(subject.precedes?(subject)).to eq(false)
|
107
|
-
state1 = new_parse_state(sample_prod, 1, origin_val)
|
108
|
-
expect(state1.precedes?(subject)).to eq(true)
|
109
|
-
state0 = new_parse_state(sample_prod, 0, origin_val)
|
110
|
-
expect(state0.precedes?(state1)).to eq(true)
|
111
|
-
expect(state0.precedes?(subject)).to eq(false)
|
112
|
-
state3 = new_parse_state(sample_prod, 3, origin_val)
|
113
|
-
expect(state3.precedes?(state0)).to eq(false)
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'should know its text representation' do
|
117
|
-
expected = 'sentence => A B . C | 3'
|
118
|
-
expect(subject.to_s).to eq(expected)
|
119
|
-
end
|
120
|
-
end # context
|
121
|
-
end # describe
|
122
|
-
end # module
|
123
|
-
end # module
|
124
|
-
|
125
|
-
# End of file
|
@@ -1,200 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../../spec_helper'
|
4
|
-
require 'stringio'
|
5
|
-
|
6
|
-
require_relative '../../../lib/rley/syntax/terminal'
|
7
|
-
require_relative '../../../lib/rley/syntax/non_terminal'
|
8
|
-
require_relative '../../../lib/rley/syntax/production'
|
9
|
-
require_relative '../../../lib/rley/base/dotted_item'
|
10
|
-
require_relative '../../../lib/rley/parser/parse_state'
|
11
|
-
require_relative '../../../lib/rley/lexical/token'
|
12
|
-
|
13
|
-
# Load the class under test
|
14
|
-
require_relative '../../../lib/rley/parser/parse_tracer'
|
15
|
-
|
16
|
-
module Rley # Open this namespace to avoid module qualifier prefixes
|
17
|
-
module Parser # Open this namespace to avoid module qualifier prefixes
|
18
|
-
describe ParseTracer do
|
19
|
-
let(:output) { StringIO.new(+'', 'w') }
|
20
|
-
let(:tpos) { Lexical::Position.new(3, 4) }
|
21
|
-
|
22
|
-
let(:token_seq) do
|
23
|
-
literals = %w[I saw John with a dog]
|
24
|
-
literals.map do |lexeme|
|
25
|
-
Lexical::Token.new(lexeme, double('fake-terminal'), tpos)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
subject { ParseTracer.new(1, output, token_seq) }
|
30
|
-
|
31
|
-
context 'Creation & initialization:' do
|
32
|
-
it 'should accept trace level 0' do
|
33
|
-
expect { ParseTracer.new(0, output, token_seq) }.not_to raise_error
|
34
|
-
expect(output.string).to eq('')
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
it 'should accept trace level 1' do
|
39
|
-
expect { ParseTracer.new(1, output, token_seq) }.not_to raise_error
|
40
|
-
expectations = <<-SNIPPET
|
41
|
-
['I', 'saw', 'John', 'with', 'a', 'dog']
|
42
|
-
|. I . saw . John . with . a . dog .|
|
43
|
-
SNIPPET
|
44
|
-
expect(output.string).to eq(expectations)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'should accept trace level 2' do
|
48
|
-
expect { ParseTracer.new(2, output, token_seq) }.not_to raise_error
|
49
|
-
expectations = <<-SNIPPET
|
50
|
-
['I', 'saw', 'John', 'with', 'a', 'dog']
|
51
|
-
|. I . saw . John . with . a . dog .|
|
52
|
-
SNIPPET
|
53
|
-
expect(output.string).to eq(expectations)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'should know the trace level' do
|
57
|
-
expect(subject.level).to eq(1)
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'should know the output stream' do
|
61
|
-
expect(subject.ostream).to eq(output)
|
62
|
-
end
|
63
|
-
end # context
|
64
|
-
|
65
|
-
context 'Provided services:' do
|
66
|
-
let(:t_a) { Syntax::Terminal.new('A') }
|
67
|
-
let(:t_b) { Syntax::Terminal.new('B') }
|
68
|
-
let(:t_c) { Syntax::Terminal.new('C') }
|
69
|
-
let(:nt_sentence) { Syntax::NonTerminal.new('sentence') }
|
70
|
-
|
71
|
-
let(:sample_prod) do
|
72
|
-
Syntax::Production.new(nt_sentence, [t_a, t_b, t_c])
|
73
|
-
end
|
74
|
-
|
75
|
-
let(:origin_val) { 3 }
|
76
|
-
let(:dotted_rule) { Base::DottedItem.new(sample_prod, 2) }
|
77
|
-
let(:complete_rule) { Base::DottedItem.new(sample_prod, 3) }
|
78
|
-
let(:sample_parse_state) { ParseState.new(dotted_rule, origin_val) }
|
79
|
-
|
80
|
-
# Factory method.
|
81
|
-
def parse_state(origin, aDottedRule)
|
82
|
-
ParseState.new(aDottedRule, origin)
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'should render a scanning step' do
|
86
|
-
# Case: token at the beginning
|
87
|
-
subject.ostream.string = +''
|
88
|
-
subject.trace_scanning(1, parse_state(0, dotted_rule))
|
89
|
-
expectations = <<-SNIPPET
|
90
|
-
|[------] . . . . .| [0:1] sentence => A B . C
|
91
|
-
SNIPPET
|
92
|
-
expect(output.string).to eq(expectations)
|
93
|
-
|
94
|
-
# Case: token in the middle
|
95
|
-
subject.ostream.string = +''
|
96
|
-
subject.trace_scanning(4, sample_parse_state)
|
97
|
-
expectations = <<-SNIPPET
|
98
|
-
|. . . [------] . .| [3:4] sentence => A B . C
|
99
|
-
SNIPPET
|
100
|
-
expect(output.string).to eq(expectations)
|
101
|
-
|
102
|
-
# Case: token at the end
|
103
|
-
subject.ostream.string = +''
|
104
|
-
subject.trace_scanning(6, parse_state(5, dotted_rule))
|
105
|
-
expectations = <<-SNIPPET
|
106
|
-
|. . . . . [------]| [5:6] sentence => A B . C
|
107
|
-
SNIPPET
|
108
|
-
expect(output.string).to eq(expectations)
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
it 'should render a prediction step' do
|
113
|
-
# Case: initial stateset
|
114
|
-
subject.ostream.string = +''
|
115
|
-
subject.trace_prediction(0, parse_state(0, dotted_rule))
|
116
|
-
expectations = <<-SNIPPET
|
117
|
-
|> . . . . . .| [0:0] sentence => A B . C
|
118
|
-
SNIPPET
|
119
|
-
expect(output.string).to eq(expectations)
|
120
|
-
|
121
|
-
# Case: stateset in the middle
|
122
|
-
subject.ostream.string = +''
|
123
|
-
subject.trace_prediction(3, sample_parse_state)
|
124
|
-
expectations = <<-SNIPPET
|
125
|
-
|. . . > . . .| [3:3] sentence => A B . C
|
126
|
-
SNIPPET
|
127
|
-
expect(output.string).to eq(expectations)
|
128
|
-
|
129
|
-
# Case: final stateset
|
130
|
-
subject.ostream.string = +''
|
131
|
-
subject.trace_prediction(6, parse_state(6, dotted_rule))
|
132
|
-
expectations = <<-SNIPPET
|
133
|
-
|. . . . . . >| [6:6] sentence => A B . C
|
134
|
-
SNIPPET
|
135
|
-
expect(output.string).to eq(expectations)
|
136
|
-
end
|
137
|
-
|
138
|
-
it 'should render a completion step' do
|
139
|
-
# Case: full parse completed
|
140
|
-
subject.ostream.string = +''
|
141
|
-
subject.trace_completion(6, parse_state(0, complete_rule))
|
142
|
-
expectations = <<-SNIPPET
|
143
|
-
|[=========================================]| [0:6] sentence => A B C .
|
144
|
-
SNIPPET
|
145
|
-
expect(output.string).to eq(expectations)
|
146
|
-
|
147
|
-
# Case: step at the start (complete)
|
148
|
-
subject.ostream.string = +''
|
149
|
-
subject.trace_completion(1, parse_state(0, complete_rule))
|
150
|
-
expectations = <<-SNIPPET
|
151
|
-
|[------] . . . . .| [0:1] sentence => A B C .
|
152
|
-
SNIPPET
|
153
|
-
expect(output.string).to eq(expectations)
|
154
|
-
|
155
|
-
# Case: step at the start (not complete)
|
156
|
-
subject.ostream.string = +''
|
157
|
-
subject.trace_completion(1, parse_state(0, dotted_rule))
|
158
|
-
expectations = <<-SNIPPET
|
159
|
-
|[------> . . . . .| [0:1] sentence => A B . C
|
160
|
-
SNIPPET
|
161
|
-
expect(output.string).to eq(expectations)
|
162
|
-
|
163
|
-
# Case: step at the middle (complete)
|
164
|
-
subject.ostream.string = +''
|
165
|
-
subject.trace_completion(4, parse_state(2, complete_rule))
|
166
|
-
expectations = <<-SNIPPET
|
167
|
-
|. . [-------------] . .| [2:4] sentence => A B C .
|
168
|
-
SNIPPET
|
169
|
-
expect(output.string).to eq(expectations)
|
170
|
-
|
171
|
-
# Case: step at the middle (not complete)
|
172
|
-
subject.ostream.string = +''
|
173
|
-
subject.trace_completion(4, parse_state(2, dotted_rule))
|
174
|
-
expectations = <<-SNIPPET
|
175
|
-
|. . [-------------> . .| [2:4] sentence => A B . C
|
176
|
-
SNIPPET
|
177
|
-
expect(output.string).to eq(expectations)
|
178
|
-
|
179
|
-
# Case: step at the end (complete)
|
180
|
-
subject.ostream.string = +''
|
181
|
-
subject.trace_completion(6, parse_state(3, complete_rule))
|
182
|
-
expectations = <<-SNIPPET
|
183
|
-
|. . . [--------------------]| [3:6] sentence => A B C .
|
184
|
-
SNIPPET
|
185
|
-
expect(output.string).to eq(expectations)
|
186
|
-
|
187
|
-
# Case: step at the end (not complete)
|
188
|
-
subject.ostream.string = +''
|
189
|
-
subject.trace_completion(6, parse_state(3, dotted_rule))
|
190
|
-
expectations = <<-SNIPPET
|
191
|
-
|. . . [-------------------->| [3:6] sentence => A B . C
|
192
|
-
SNIPPET
|
193
|
-
expect(output.string).to eq(expectations)
|
194
|
-
end
|
195
|
-
end # context
|
196
|
-
end # describe
|
197
|
-
end # module
|
198
|
-
end # module
|
199
|
-
|
200
|
-
# End of file
|