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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/lib/dendroid/formatters/ascii_tree.rb +142 -0
  4. data/lib/dendroid/formatters/base_formatter.rb +25 -0
  5. data/lib/dendroid/formatters/bracket_notation.rb +50 -0
  6. data/lib/dendroid/grm_analysis/dotted_item.rb +46 -30
  7. data/lib/dendroid/grm_analysis/grm_analyzer.rb +2 -4
  8. data/lib/dendroid/grm_analysis/{choice_items.rb → rule_items.rb} +10 -10
  9. data/lib/dendroid/grm_dsl/base_grm_builder.rb +3 -4
  10. data/lib/dendroid/parsing/and_node.rb +56 -0
  11. data/lib/dendroid/parsing/chart_walker.rb +293 -0
  12. data/lib/dendroid/parsing/composite_parse_node.rb +21 -0
  13. data/lib/dendroid/parsing/empty_rule_node.rb +28 -0
  14. data/lib/dendroid/parsing/or_node.rb +51 -0
  15. data/lib/dendroid/parsing/parse_node.rb +26 -0
  16. data/lib/dendroid/parsing/parse_tree_visitor.rb +127 -0
  17. data/lib/dendroid/parsing/parser.rb +185 -0
  18. data/lib/dendroid/parsing/terminal_node.rb +32 -0
  19. data/lib/dendroid/parsing/walk_progress.rb +117 -0
  20. data/lib/dendroid/recognizer/chart.rb +8 -0
  21. data/lib/dendroid/recognizer/e_item.rb +21 -2
  22. data/lib/dendroid/recognizer/item_set.rb +7 -2
  23. data/lib/dendroid/recognizer/recognizer.rb +33 -20
  24. data/lib/dendroid/syntax/grammar.rb +1 -1
  25. data/lib/dendroid/syntax/rule.rb +71 -13
  26. data/spec/dendroid/grm_analysis/dotted_item_spec.rb +59 -47
  27. data/spec/dendroid/grm_analysis/{choice_items_spec.rb → rule_items_spec.rb} +5 -6
  28. data/spec/dendroid/parsing/chart_walker_spec.rb +223 -0
  29. data/spec/dendroid/parsing/terminal_node_spec.rb +36 -0
  30. data/spec/dendroid/recognizer/e_item_spec.rb +5 -5
  31. data/spec/dendroid/recognizer/item_set_spec.rb +16 -8
  32. data/spec/dendroid/recognizer/recognizer_spec.rb +57 -5
  33. data/spec/dendroid/support/sample_grammars.rb +2 -0
  34. data/spec/dendroid/syntax/grammar_spec.rb +16 -21
  35. data/spec/dendroid/syntax/rule_spec.rb +56 -7
  36. data/version.txt +1 -1
  37. metadata +20 -13
  38. data/lib/dendroid/grm_analysis/alternative_item.rb +0 -70
  39. data/lib/dendroid/grm_analysis/production_items.rb +0 -55
  40. data/lib/dendroid/syntax/choice.rb +0 -95
  41. data/lib/dendroid/syntax/production.rb +0 -82
  42. data/spec/dendroid/grm_analysis/alternative_item_spec.rb +0 -12
  43. data/spec/dendroid/grm_analysis/production_items_spec.rb +0 -68
  44. data/spec/dendroid/syntax/choice_spec.rb +0 -68
  45. 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