dendroid 0.1.00 → 0.2.00
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/CHANGELOG.md +3 -0
- data/lib/dendroid/formatters/ascii_tree.rb +142 -0
- data/lib/dendroid/formatters/base_formatter.rb +25 -0
- data/lib/dendroid/formatters/bracket_notation.rb +50 -0
- data/lib/dendroid/grm_analysis/dotted_item.rb +46 -30
- data/lib/dendroid/grm_analysis/grm_analyzer.rb +2 -4
- data/lib/dendroid/grm_analysis/{choice_items.rb → rule_items.rb} +10 -10
- data/lib/dendroid/grm_dsl/base_grm_builder.rb +3 -4
- data/lib/dendroid/parsing/and_node.rb +56 -0
- data/lib/dendroid/parsing/chart_walker.rb +293 -0
- data/lib/dendroid/parsing/composite_parse_node.rb +21 -0
- data/lib/dendroid/parsing/empty_rule_node.rb +28 -0
- data/lib/dendroid/parsing/or_node.rb +51 -0
- data/lib/dendroid/parsing/parse_node.rb +26 -0
- data/lib/dendroid/parsing/parse_tree_visitor.rb +127 -0
- data/lib/dendroid/parsing/parser.rb +185 -0
- data/lib/dendroid/parsing/terminal_node.rb +32 -0
- data/lib/dendroid/parsing/walk_progress.rb +117 -0
- data/lib/dendroid/recognizer/chart.rb +8 -0
- data/lib/dendroid/recognizer/e_item.rb +21 -2
- data/lib/dendroid/recognizer/item_set.rb +7 -2
- data/lib/dendroid/recognizer/recognizer.rb +33 -20
- data/lib/dendroid/syntax/grammar.rb +1 -1
- data/lib/dendroid/syntax/rule.rb +71 -13
- data/spec/dendroid/grm_analysis/dotted_item_spec.rb +59 -47
- data/spec/dendroid/grm_analysis/{choice_items_spec.rb → rule_items_spec.rb} +5 -6
- data/spec/dendroid/parsing/chart_walker_spec.rb +223 -0
- data/spec/dendroid/parsing/terminal_node_spec.rb +36 -0
- data/spec/dendroid/recognizer/e_item_spec.rb +5 -5
- data/spec/dendroid/recognizer/item_set_spec.rb +16 -8
- data/spec/dendroid/recognizer/recognizer_spec.rb +57 -5
- data/spec/dendroid/support/sample_grammars.rb +2 -0
- data/spec/dendroid/syntax/grammar_spec.rb +16 -21
- data/spec/dendroid/syntax/rule_spec.rb +56 -7
- data/version.txt +1 -1
- metadata +20 -13
- data/lib/dendroid/grm_analysis/alternative_item.rb +0 -70
- data/lib/dendroid/grm_analysis/production_items.rb +0 -55
- data/lib/dendroid/syntax/choice.rb +0 -95
- data/lib/dendroid/syntax/production.rb +0 -82
- data/spec/dendroid/grm_analysis/alternative_item_spec.rb +0 -12
- data/spec/dendroid/grm_analysis/production_items_spec.rb +0 -68
- data/spec/dendroid/syntax/choice_spec.rb +0 -68
- data/spec/dendroid/syntax/production_spec.rb +0 -92
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '..\..\spec_helper'
|
4
|
-
require_relative '..\..\..\lib\dendroid\syntax\terminal'
|
5
|
-
require_relative '..\..\..\lib\dendroid\syntax\non_terminal'
|
6
|
-
require_relative '..\..\..\lib\dendroid\syntax\symbol_seq'
|
7
|
-
require_relative '..\..\..\lib\dendroid\syntax\choice'
|
8
|
-
|
9
|
-
describe Dendroid::Syntax::Choice do
|
10
|
-
let(:num_symb) { Dendroid::Syntax::Terminal.new('NUMBER') }
|
11
|
-
let(:plus_symb) { Dendroid::Syntax::Terminal.new('PLUS') }
|
12
|
-
let(:minus_symb) { Dendroid::Syntax::Terminal.new('MINUS') }
|
13
|
-
let(:expr_symb) { Dendroid::Syntax::NonTerminal.new('expression') }
|
14
|
-
let(:foo_symb) { Dendroid::Syntax::NonTerminal.new('foo') }
|
15
|
-
let(:alt1) { Dendroid::Syntax::SymbolSeq.new([num_symb, plus_symb, num_symb]) }
|
16
|
-
let(:alt2) { Dendroid::Syntax::SymbolSeq.new([num_symb, minus_symb, num_symb]) }
|
17
|
-
let(:empty_body) { Dendroid::Syntax::SymbolSeq.new([]) }
|
18
|
-
|
19
|
-
# Implements a choice rule:
|
20
|
-
# expression => NUMBER PLUS NUMBER
|
21
|
-
# | NUMBER MINUS NUMBER
|
22
|
-
# | epsilon
|
23
|
-
subject { described_class.new(expr_symb, [alt1, alt2, empty_body]) }
|
24
|
-
|
25
|
-
context 'Initialization:' do
|
26
|
-
it 'is initialized with a head and alternatives' do
|
27
|
-
expect { described_class.new(expr_symb, [alt1, alt2, empty_body]) }.not_to raise_error
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'knows its alternatives' do
|
31
|
-
expect(subject.alternatives).to eq([alt1, alt2, empty_body])
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'renders a String representation of itself' do
|
35
|
-
expectation = 'expression => NUMBER PLUS NUMBER | NUMBER MINUS NUMBER | '
|
36
|
-
expect(subject.to_s).to eq(expectation)
|
37
|
-
end
|
38
|
-
end # context
|
39
|
-
|
40
|
-
context 'Provided services:' do
|
41
|
-
it 'knows its terminal members' do
|
42
|
-
expect(subject.terminals).to eq([num_symb, plus_symb, minus_symb])
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'knows its non-terminal members' do
|
46
|
-
expect(subject.nonterminals).to be_empty
|
47
|
-
|
48
|
-
my_alt1 = Dendroid::Syntax::SymbolSeq.new([expr_symb, plus_symb, expr_symb])
|
49
|
-
my_alt2 = Dendroid::Syntax::SymbolSeq.new([foo_symb, minus_symb, expr_symb])
|
50
|
-
instance = described_class.new(foo_symb, [my_alt1, my_alt2])
|
51
|
-
expect(instance.nonterminals).to eq([expr_symb, foo_symb])
|
52
|
-
end
|
53
|
-
end # context
|
54
|
-
|
55
|
-
context 'Errors:' do
|
56
|
-
it 'fails when initialized with one alternative only' do
|
57
|
-
err = StandardError
|
58
|
-
err_msg = 'The choice for `expression` must have at least two alternatives.'
|
59
|
-
expect { described_class.new(expr_symb, [alt1]) }.to raise_error(err, err_msg)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'fails in presence of duplicate rhs' do
|
63
|
-
err = StandardError
|
64
|
-
err_msg = 'Duplicate alternatives: expression => NUMBER PLUS NUMBER'
|
65
|
-
expect { described_class.new(expr_symb, [alt1, alt2, alt1]) }.to raise_error(err, err_msg)
|
66
|
-
end
|
67
|
-
end # context
|
68
|
-
end # describe
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '..\..\spec_helper'
|
4
|
-
require_relative '..\..\..\lib\dendroid\syntax\terminal'
|
5
|
-
require_relative '..\..\..\lib\dendroid\syntax\non_terminal'
|
6
|
-
require_relative '..\..\..\lib\dendroid\syntax\symbol_seq'
|
7
|
-
require_relative '..\..\..\lib\dendroid\syntax\production'
|
8
|
-
|
9
|
-
describe Dendroid::Syntax::Production do
|
10
|
-
let(:num_symb) { Dendroid::Syntax::Terminal.new('NUMBER') }
|
11
|
-
let(:plus_symb) { Dendroid::Syntax::Terminal.new('PLUS') }
|
12
|
-
let(:expr_symb) { Dendroid::Syntax::NonTerminal.new('expression') }
|
13
|
-
let(:foo_symb) { Dendroid::Syntax::NonTerminal.new('foo') }
|
14
|
-
let(:rhs) { Dendroid::Syntax::SymbolSeq.new([num_symb, plus_symb, num_symb]) }
|
15
|
-
let(:cyclic_rhs) { Dendroid::Syntax::SymbolSeq.new([foo_symb]) }
|
16
|
-
let(:empty_body) { Dendroid::Syntax::SymbolSeq.new([]) }
|
17
|
-
|
18
|
-
# Implements a production rule: expression => NUMBER PLUS NUMBER
|
19
|
-
subject { described_class.new(expr_symb, rhs) }
|
20
|
-
|
21
|
-
context 'Initialization:' do
|
22
|
-
it 'is initialized with a head and a body' do
|
23
|
-
expect { described_class.new(expr_symb, rhs) }.not_to raise_error
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'knows its body (aka rhs)' do
|
27
|
-
expect(subject.body).to eq(rhs)
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'renders a String representation of itself' do
|
31
|
-
expect(subject.to_s).to eq('expression => NUMBER PLUS NUMBER')
|
32
|
-
end
|
33
|
-
end # context
|
34
|
-
|
35
|
-
context 'Provided services:' do
|
36
|
-
it 'knows whether its body empty is empty or not' do
|
37
|
-
expect(described_class.new(expr_symb, empty_body).empty?).to be_truthy
|
38
|
-
expect(subject.empty?).to be_falsey
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'knows its non-terminal members' do
|
42
|
-
foo_rhs = Dendroid::Syntax::SymbolSeq.new([expr_symb, plus_symb, expr_symb])
|
43
|
-
instance = described_class.new(foo_symb, foo_rhs)
|
44
|
-
expect(instance.nonterminals).to eq([expr_symb])
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'knows its terminal members' do
|
48
|
-
expect(subject.terminals).to eq([num_symb, plus_symb])
|
49
|
-
end
|
50
|
-
|
51
|
-
# rubocop: disable Lint/BinaryOperatorWithIdenticalOperands
|
52
|
-
it 'can compare with another production' do
|
53
|
-
expect(subject == subject).to be_truthy
|
54
|
-
|
55
|
-
same = described_class.new(expr_symb, rhs)
|
56
|
-
expect(subject == same).to be_truthy
|
57
|
-
|
58
|
-
# Different lhs, same rhs
|
59
|
-
different_lhs = described_class.new(foo_symb, rhs)
|
60
|
-
expect(subject == different_lhs).to be_falsey
|
61
|
-
|
62
|
-
# Same lhs, different rhs
|
63
|
-
different_rhs = described_class.new(expr_symb, empty_body)
|
64
|
-
expect(subject == different_rhs).to be_falsey
|
65
|
-
|
66
|
-
# Two productions with same lhs and empty bodies
|
67
|
-
empty = described_class.new(expr_symb, empty_body)
|
68
|
-
void = described_class.new(expr_symb, Dendroid::Syntax::SymbolSeq.new([]))
|
69
|
-
expect(empty == void).to be_truthy
|
70
|
-
|
71
|
-
# Two productions with distinct lhs and empty bodies
|
72
|
-
empty = described_class.new(expr_symb, empty_body)
|
73
|
-
void = described_class.new(foo_symb, Dendroid::Syntax::SymbolSeq.new([]))
|
74
|
-
expect(empty == void).to be_falsey
|
75
|
-
end
|
76
|
-
# rubocop: enable Lint/BinaryOperatorWithIdenticalOperands
|
77
|
-
end # context
|
78
|
-
|
79
|
-
context 'Errors:' do
|
80
|
-
it "fails when rhs isn't initialized with a SymbolSeq" do
|
81
|
-
err = StandardError
|
82
|
-
err_msg = 'Expecting a SymbolSeq, found a String instead.'
|
83
|
-
expect { described_class.new(foo_symb, 'bad') }.to raise_error err, err_msg
|
84
|
-
end
|
85
|
-
|
86
|
-
it 'fails when the production is cyclic' do
|
87
|
-
err = StandardError
|
88
|
-
err_msg = 'Cyclic rules of the kind foo => foo are not allowed.'
|
89
|
-
expect { described_class.new(foo_symb, cyclic_rhs) }.to raise_error err, err_msg
|
90
|
-
end
|
91
|
-
end # context
|
92
|
-
end # describe
|