dendroid 0.0.2 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23f7c3fcf4a7f0df335e5b2fbc7f25f89a60f4d66cc9bfd1ce37680fbb133b83
4
- data.tar.gz: fc4a399d2a5812d4c0e01b28bc261e810386b3d54c353ba2e54190d3df508e3f
3
+ metadata.gz: a28b9efefb235a669b37c24f587704cc94b7a10f411eafdeef418094013abfc2
4
+ data.tar.gz: 1e316ac1c14b8b81ee2a3acf96a3f04d3e772e72f0a062976150ea5def7080f6
5
5
  SHA512:
6
- metadata.gz: c4f9ec0db43dcf581d2c5a3866fb383f757bd0a99b4526348b41326a22b0c39b04200768b1cb7a1dfd03ae3272d60de0fc09f73c9a7d9df3269bdf1721f8f19b
7
- data.tar.gz: dd5a819b7946149c38e39822489d2ef08838abb87f6f6e549e2dbade55fa77edf99d91503664506bfe0b07a5c66d5408a7b409c0b090297f70d488696ecd88bc
6
+ metadata.gz: 72b4df1de4b537b3bb5ae1d00f56a7cde86627c5b5b2205390a02c824809bfd81ee493ee70ca01d08ea3874e9dc04beb66f09366b186fb133a4250e426281553
7
+ data.tar.gz: 5cb5126a0f116d86a91f2a2138dac2330bfaf3911548324947196d768e0ec4e45a897360ce2ab3d31e48497bd24e2fdefdbfc365c28dda5f953f20ea3a16a563
data/.rubocop.yml CHANGED
@@ -1,3 +1,7 @@
1
+ Layout/EndOfLine:
2
+ Enabled: true
3
+ EnforcedStyle: lf
4
+
1
5
  Metrics/BlockLength:
2
6
  Enabled: true
3
7
  Max: 50
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rule'
4
+
5
+ module Dendroid
6
+ module Syntax
7
+ # A specialization of the Rule class.
8
+ # A production is the unique rule for the non-terminal symbol
9
+ # at its left-hand side (lhs).
10
+ class Production < Rule
11
+ # @return [Dendroid::Syntax::SymbolSeq]
12
+ attr_reader :body
13
+
14
+ # Create a Production instance.
15
+ # @param lhs [Dendroid::Syntax::NonTerminal] The left-hand side of the rule.
16
+ # @param rhs [Dendroid::Syntax::SymbolSeq] the sequence of symbols on rhs.
17
+ def initialize(lhs, rhs)
18
+ super(lhs)
19
+ @body = valid_body(rhs)
20
+ end
21
+
22
+ # Predicate method to check whether the rule body (its rhs) is empty.
23
+ # @return [Boolean]
24
+ def empty?
25
+ body.empty?
26
+ end
27
+
28
+ # Predicate method to check whether the rule has alternatives
29
+ # @return [FalseClass]
30
+ def choice?
31
+ false
32
+ end
33
+
34
+ # Predicate method to check whether the production rule body is productive.
35
+ # It is productive when it is empty or all of its rhs members are productive too.
36
+ # @return [Boolean, NilClass]
37
+ def productive?
38
+ if @productive.nil?
39
+ if body.productive?
40
+ self.productive = true
41
+ else
42
+ nil
43
+ end
44
+ else
45
+ @productive
46
+ end
47
+ end
48
+
49
+ # Mark the production rule as non-productive.
50
+ def non_productive
51
+ self.productive = false
52
+ end
53
+
54
+ # Return the text representation of the production rule
55
+ # @return [String]
56
+ def to_s
57
+ "#{head} => #{body}"
58
+ end
59
+
60
+ # Equality operator
61
+ # Two production rules are equal when their head and rhs are equal.
62
+ # @return [Boolean]
63
+ def ==(other)
64
+ return true if equal?(other)
65
+
66
+ (head == other.head) && (body == other.body)
67
+ end
68
+
69
+ # Returns an array with the symbol sequence of its rhs
70
+ # @return [Array<Dendroid::Syntax::SymbolSeq>]
71
+ def rhs
72
+ [body]
73
+ end
74
+
75
+ private
76
+
77
+ def valid_body(rhs)
78
+ raise StandardError unless rhs.is_a?(SymbolSeq)
79
+
80
+ if rhs.size == 1 && lhs == rhs.first
81
+ # Forbid cyclic rules (e.g. A => A)
82
+ raise StandardError.new, "Cyclic rule of the kind #{lhs} => #{lhs} is not allowed."
83
+ end
84
+
85
+ rhs
86
+ end
87
+
88
+ def productive=(val)
89
+ @productive = val
90
+ lhs.productive = val
91
+ end
92
+ end # class
93
+ end # module
94
+ end # module
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dendroid
4
+ module Syntax
5
+ # In a context-free grammar, a rule has its left-hand side (LHS)
6
+ # that consists solely of one non-terminal symbol.
7
+ # and the right-hand side (RHS) consists of one or more sequence of symbols.
8
+ # The symbols in RHS can be either terminal or non-terminal symbols.
9
+ # The rule stipulates that the LHS is equivalent to the RHS,
10
+ # in other words every occurrence of the LHS can be substituted to
11
+ # corresponding RHS.
12
+ class Rule
13
+ # @return [Dendroid::Syntax::NonTerminal] The left-hand side of the rule.
14
+ attr_reader :head
15
+ alias lhs head
16
+
17
+ # Create a Rule instance.
18
+ # @param lhs [Dendroid::Syntax::NonTerminal] The left-hand side of the rule.
19
+ def initialize(lhs)
20
+ @head = valid_head(lhs)
21
+ end
22
+
23
+ # Return the text representation of the rule
24
+ # @return [String]
25
+ def to_s
26
+ head.to_s
27
+ end
28
+
29
+ # The set of all grammar symbols that occur in the rhs.
30
+ # @return [Array<Dendroid::Syntax::GrmSymbol>]
31
+ def rhs_symbols
32
+ symbols = rhs.reduce([]) do |result, alt|
33
+ result.concat(alt.members)
34
+ end
35
+ symbols.uniq
36
+ end
37
+
38
+ # The set of all non-terminal symbols that occur in the rhs.
39
+ # @return [Array<Dendroid::Syntax::NonTerminal>]
40
+ def nonterminals
41
+ rhs_symbols.reject(&:terminal?)
42
+ end
43
+
44
+ # The set of all terminal symbols that occur in the rhs.
45
+ # @return [Array<Dendroid::Syntax::Terminal>]
46
+ def terminals
47
+ rhs_symbols.select(&:terminal?)
48
+ end
49
+
50
+ private
51
+
52
+ def valid_head(lhs)
53
+ if lhs.terminal?
54
+ err_msg = "Terminal symbol '#{lhs}' may not be on left-side of a rule."
55
+ raise StandardError, err_msg
56
+ end
57
+
58
+ lhs
59
+ end
60
+ end # class
61
+ end # module
62
+ end # module
@@ -0,0 +1,77 @@
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(:empty_body) { Dendroid::Syntax::SymbolSeq.new([]) }
16
+
17
+ # Implements a production rule: expression => NUMBER PLUS NUMBER
18
+ subject { described_class.new(expr_symb, rhs) }
19
+
20
+ context 'Initialization:' do
21
+ it 'is initialized with a head and a body' do
22
+ expect { described_class.new(expr_symb, rhs) }.not_to raise_error
23
+ end
24
+
25
+ it 'knows its body (aka rhs)' do
26
+ expect(subject.body).to eq(rhs)
27
+ end
28
+
29
+ it 'renders a String representation of itself' do
30
+ expect(subject.to_s).to eq('expression => NUMBER PLUS NUMBER')
31
+ end
32
+ end # context
33
+
34
+ context 'Provided services:' do
35
+ it 'knows whether its body empty is empty or not' do
36
+ expect(described_class.new(expr_symb, empty_body).empty?).to be_truthy
37
+ expect(subject.empty?).to be_falsey
38
+ end
39
+
40
+ it 'knows its non-terminal members' do
41
+ foo_rhs = Dendroid::Syntax::SymbolSeq.new([expr_symb, plus_symb, expr_symb])
42
+ instance = described_class.new(foo_symb, foo_rhs)
43
+ expect(instance.nonterminals).to eq([expr_symb])
44
+ end
45
+
46
+ it 'knows its terminal members' do
47
+ expect(subject.terminals).to eq([num_symb, plus_symb])
48
+ end
49
+
50
+ # rubocop: disable Lint/BinaryOperatorWithIdenticalOperands
51
+ it 'can compare with another production' do
52
+ expect(subject == subject).to be_truthy
53
+
54
+ same = described_class.new(expr_symb, rhs)
55
+ expect(subject == same).to be_truthy
56
+
57
+ # Different lhs, same rhs
58
+ different_lhs = described_class.new(foo_symb, rhs)
59
+ expect(subject == different_lhs).to be_falsey
60
+
61
+ # Same lhs, different rhs
62
+ different_rhs = described_class.new(expr_symb, empty_body)
63
+ expect(subject == different_rhs).to be_falsey
64
+
65
+ # Two productions with same lhs and empty bodies
66
+ empty = described_class.new(expr_symb, empty_body)
67
+ void = described_class.new(expr_symb, Dendroid::Syntax::SymbolSeq.new([]))
68
+ expect(empty == void).to be_truthy
69
+
70
+ # Two productions with distinct lhs and empty bodies
71
+ empty = described_class.new(expr_symb, empty_body)
72
+ void = described_class.new(foo_symb, Dendroid::Syntax::SymbolSeq.new([]))
73
+ expect(empty == void).to be_falsey
74
+ end
75
+ # rubocop: enable Lint/BinaryOperatorWithIdenticalOperands
76
+ end # context
77
+ end # describe
@@ -0,0 +1,23 @@
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\rule'
7
+
8
+ describe Dendroid::Syntax::Rule do
9
+ let(:num_symb) { Dendroid::Syntax::Terminal.new('NUMBER') }
10
+ let(:expr_symb) { Dendroid::Syntax::NonTerminal.new('expression') }
11
+
12
+ subject { described_class.new(expr_symb) }
13
+
14
+ context 'Initialization:' do
15
+ it 'is initialized with a non-terminal' do
16
+ expect { described_class.new(expr_symb) }.not_to raise_error
17
+ end
18
+
19
+ it 'knows its head (aka lhs)' do
20
+ expect(subject.head).to eq(expr_symb)
21
+ end
22
+ end # context
23
+ end # describe
data/version.txt CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.4
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dendroid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
@@ -25,10 +25,14 @@ files:
25
25
  - lib/dendroid/dendroid.rb
26
26
  - lib/dendroid/syntax/grm_symbol.rb
27
27
  - lib/dendroid/syntax/non_terminal.rb
28
+ - lib/dendroid/syntax/production.rb
29
+ - lib/dendroid/syntax/rule.rb
28
30
  - lib/dendroid/syntax/symbol_seq.rb
29
31
  - lib/dendroid/syntax/terminal.rb
30
32
  - spec/dendroid/syntax/grm_symbol_spec.rb
31
33
  - spec/dendroid/syntax/non_terminal_spec.rb
34
+ - spec/dendroid/syntax/production_spec.rb
35
+ - spec/dendroid/syntax/rule_spec.rb
32
36
  - spec/dendroid/syntax/symbol_seq_spec.rb
33
37
  - spec/dendroid/syntax/terminal_spec.rb
34
38
  - spec/spec_helper.rb