sequitur 0.1.18 → 0.1.23

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.
@@ -1,101 +1,99 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'production'
2
4
  require_relative 'grammar_visitor'
3
5
 
4
6
  module Sequitur # Module for classes implementing the Sequitur algorithm
5
- # A dynamic grammar is a context-free grammar that can be built incrementally.
6
- # Formally, a grammar has:
7
- # One start production
8
- # Zero or more other productions
9
- # Each production has a rhs that is a sequence of grammar symbols.
10
- # Grammar symbols are categorized into
11
- # -terminal symbols (i.e. String, Ruby Symbol,...)
12
- # -non-terminal symbols (i.e. ProductionRef)
13
- class DynamicGrammar
14
- # Link to the start production.
15
- attr_reader(:start)
16
-
17
- # The set of production rules of the grammar
18
- attr_reader(:productions)
19
-
20
- # nodoc Trace the execution of the algorithm.
21
- attr(:trace)
22
-
23
-
24
- # Constructor.
25
- # Build a grammar with one empty rule as start/start rule.
26
- def initialize()
27
- @start = Production.new
28
- @productions = [ start ]
29
- @trace = false
30
- end
31
-
32
- # Emit a text representation of the grammar.
33
- # Each production rule is emitted per line.
34
- # @return [String]
35
- def to_string()
36
- rule_text = productions.map(&:to_string).join("\n")
37
- return rule_text
38
- end
39
-
40
-
41
- # Add a given production to the grammar.
42
- # @param aProduction [Production]
43
- def add_production(aProduction)
44
- # TODO: remove output
45
- puts "Adding #{aProduction.object_id}" if trace
46
- puts aProduction.to_string if trace
47
- productions << aProduction
48
- end
49
-
50
-
51
- # Remove a production with given index from the grammar
52
- # @param anIndex [Fixnum]
53
- # @return [Production] the production removed from the grammar.
54
- def remove_production(anIndex)
55
- puts "Before production removal #{productions[anIndex].object_id}" if trace
56
- puts to_string if trace
57
- prod = productions.delete_at(anIndex)
58
- # TODO: remove output
59
- puts('Removed: ' + prod.to_string) if trace
60
- prod.clear_rhs
61
-
62
- return prod
63
- end
64
-
65
-
66
- # Add the given token to the grammar.
67
- # Append the token to the rhs of the start/start rule.
68
- # @param aToken [Object] input token to add
69
- def add_token(aToken)
70
- append_symbol_to(start, aToken)
71
- end
72
-
73
- # Part of the 'visitee' role in the Visitor design pattern.
74
- # A visitee is expected to accept the visit from a visitor object
75
- # @param aVisitor [GrammarVisitor] the visitor object
76
- def accept(aVisitor)
77
- aVisitor.start_visit_grammar(self)
78
-
79
- # Let's proceed with the visit of productions
80
- productions.each { |prod| prod.accept(aVisitor) }
81
-
82
- aVisitor.end_visit_grammar(self)
83
- end
84
-
85
- # Factory method. Returns a visitor for this grammar.
86
- # @return [GrammarVisitor]
87
- def visitor()
88
- return GrammarVisitor.new(self)
89
- end
90
-
91
- protected
92
-
93
- # Append a given symbol to the rhs of passed production.
94
- # @param aProduction [Production]
95
- # @param aSymbol [Object]
96
- def append_symbol_to(aProduction, aSymbol)
97
- aProduction.append_symbol(aSymbol)
98
- end
99
- end # class
7
+ # A dynamic grammar is a context-free grammar that can be built incrementally.
8
+ # Formally, a grammar has:
9
+ # One start production
10
+ # Zero or more other productions
11
+ # Each production has a rhs that is a sequence of grammar symbols.
12
+ # Grammar symbols are categorized into
13
+ # -terminal symbols (i.e. String, Ruby Symbol,...)
14
+ # -non-terminal symbols (i.e. ProductionRef)
15
+ class DynamicGrammar
16
+ # Link to the start production.
17
+ attr_reader(:start)
18
+
19
+ # The set of production rules of the grammar
20
+ attr_reader(:productions)
21
+
22
+ # nodoc Trace the execution of the algorithm.
23
+ attr_accessor(:trace)
24
+
25
+ # Constructor.
26
+ # Build a grammar with one empty rule as start/start rule.
27
+ def initialize
28
+ @start = Production.new
29
+ @productions = [start]
30
+ @trace = false
31
+ end
32
+
33
+ # Emit a text representation of the grammar.
34
+ # Each production rule is emitted per line.
35
+ # @return [String]
36
+ def to_string
37
+ rule_text = productions.map(&:to_string).join("\n")
38
+ return rule_text
39
+ end
40
+
41
+ # Add a given production to the grammar.
42
+ # @param aProduction [Production]
43
+ def add_production(aProduction)
44
+ # TODO: remove output
45
+ puts "Adding #{aProduction.object_id}" if trace
46
+ puts aProduction.to_string if trace
47
+ productions << aProduction
48
+ end
49
+
50
+ # Remove a production with given index from the grammar
51
+ # @param anIndex [Fixnum]
52
+ # @return [Production] the production removed from the grammar.
53
+ def remove_production(anIndex)
54
+ puts "Before production removal #{productions[anIndex].object_id}" if trace
55
+ puts to_string if trace
56
+ prod = productions.delete_at(anIndex)
57
+ # TODO: remove output
58
+ puts("Removed: #{prod.to_string}") if trace
59
+ prod.clear_rhs
60
+
61
+ return prod
62
+ end
63
+
64
+ # Add the given token to the grammar.
65
+ # Append the token to the rhs of the start/start rule.
66
+ # @param aToken [Object] input token to add
67
+ def add_token(aToken)
68
+ append_symbol_to(start, aToken)
69
+ end
70
+
71
+ # Part of the 'visitee' role in the Visitor design pattern.
72
+ # A visitee is expected to accept the visit from a visitor object
73
+ # @param aVisitor [GrammarVisitor] the visitor object
74
+ def accept(aVisitor)
75
+ aVisitor.start_visit_grammar(self)
76
+
77
+ # Let's proceed with the visit of productions
78
+ productions.each { |prod| prod.accept(aVisitor) }
79
+
80
+ aVisitor.end_visit_grammar(self)
81
+ end
82
+
83
+ # Factory method. Returns a visitor for this grammar.
84
+ # @return [GrammarVisitor]
85
+ def visitor
86
+ return GrammarVisitor.new(self)
87
+ end
88
+
89
+ protected
90
+
91
+ # Append a given symbol to the rhs of passed production.
92
+ # @param aProduction [Production]
93
+ # @param aSymbol [Object]
94
+ def append_symbol_to(aProduction, aSymbol)
95
+ aProduction.append_symbol(aSymbol)
96
+ end
97
+ end # class
100
98
  end # module
101
99
  # End of file
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequitur
2
4
  # Namespace dedicated to grammar formatters.
3
5
  module Formatter
4
6
  # Superclass for grammar formatters.
5
7
  class BaseFormatter
6
8
  # The IO output stream in which the formatter's result will be sent.
7
- attr(:output)
9
+ attr_accessor(:output)
8
10
 
9
11
  # Constructor.
10
12
  # @param anIO [IO] an output IO where the formatter's result will
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'base_formatter'
2
4
 
3
5
  module Sequitur
@@ -72,7 +74,7 @@ module Sequitur
72
74
  private
73
75
 
74
76
  # Read accessor of the production lookup
75
- def prod_lookup()
77
+ def prod_lookup
76
78
  return @prod_lookup
77
79
  end
78
80
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'base_formatter'
2
4
 
3
5
 
@@ -13,7 +15,7 @@ module Sequitur
13
15
  # formatter.run(some_grammar.visitor)
14
16
  class Debug < BaseFormatter
15
17
  # Current indentation level
16
- attr(:indentation)
18
+ attr_accessor(:indentation)
17
19
 
18
20
  # Constructor.
19
21
  # @param anIO [IO] The output stream to which the rendered grammar
@@ -109,11 +111,11 @@ module Sequitur
109
111
 
110
112
  private
111
113
 
112
- def indent()
114
+ def indent
113
115
  @indentation += 1
114
116
  end
115
117
 
116
- def dedent()
118
+ def dedent
117
119
  @indentation -= 1
118
120
  end
119
121
 
@@ -1,104 +1,105 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequitur # Module for classes implementing the Sequitur algorithm
2
4
  # A visitor class dedicated in the visit of Grammar.
3
- class GrammarVisitor
4
- # Link to the grammar to visit
5
- attr_reader(:grammar)
6
-
7
- # List of objects that subscribed to the visit event notification.
8
- attr_reader(:subscribers)
9
-
10
- # Build a visitor for the given grammar.
11
- # @param aGrammar [DynamicGrammar-like] the grammar to visit.
12
- def initialize(aGrammar)
13
- @grammar = aGrammar
14
- @subscribers = []
15
- end
16
-
17
- # Add a subscriber for the visit event notification.
18
- # @param aSubscriber [Object]
19
- def subscribe(aSubscriber)
20
- subscribers << aSubscriber
21
- end
22
-
23
- # Remove the given object from the subscription list.
24
- # The object won't be notified of visit events.
25
- # @param aSubscriber [Object]
26
- def unsubscribe(aSubscriber)
27
- subscribers.delete_if { |entry| entry == aSubscriber }
28
- end
29
-
30
- # The signal to start the visit.
31
- def start()
32
- grammar.accept(self)
33
- end
34
-
35
-
36
- # Visit event. The visitor is about to visit the grammar.
37
- # @param aGrammar [DynamicGrammar-like] the grammar to visit.
38
- def start_visit_grammar(aGrammar)
39
- broadcast(:before_grammar, aGrammar)
40
- end
41
-
42
-
43
- # Visit event. The visitor is about to visit the given production.
44
- # @param aProduction [Production] the production to visit.
45
- def start_visit_production(aProduction)
46
- broadcast(:before_production, aProduction)
47
- end
48
-
49
- # Visit event. The visitor is about to visit the given rhs of production.
50
- # @param rhs [SymbolSequence] the rhs of a production to visit.
51
- def start_visit_rhs(rhs)
52
- broadcast(:before_rhs, rhs)
53
- end
54
-
55
- # Visit event. The visitor is visiting the
56
- # given reference production (= non-terminal symbol).
57
- # @param aProdRef [ProductionRef] the production reference to visit.
58
- def visit_prod_ref(aProdRef)
59
- production = aProdRef.production
60
- broadcast(:before_non_terminal, production)
61
- broadcast(:after_non_terminal, production)
62
- end
63
-
64
- # Visit event. The visitor is visiting the
65
- # given terminal symbol.
66
- # @param aTerminal [Object] the terminal to visit.
67
- def visit_terminal(aTerminal)
68
- broadcast(:before_terminal, aTerminal)
69
- broadcast(:after_terminal, aTerminal)
70
- end
71
-
72
- # Visit event. The visitor has completed its visit of the given rhs.
73
- # @param rhs [SymbolSequence] the rhs of a production to visit.
74
- def end_visit_rhs(rhs)
75
- broadcast(:after_rhs, rhs)
76
- end
77
-
78
- # Visit event. The visitor has completed its visit of the given production.
79
- # @param aProduction [Production] the production to visit.
80
- def end_visit_production(aProduction)
81
- broadcast(:after_production, aProduction)
82
- end
83
-
84
- # Visit event. The visitor has completed the visit of the grammar.
85
- # @param aGrammar [DynamicGrammar-like] the grammar to visit.
86
- def end_visit_grammar(aGrammar)
87
- broadcast(:after_grammar, aGrammar)
88
- end
89
-
90
- private
91
-
92
- # Send a notification to all subscribers.
93
- # @param msg [Symbol] event to notify
94
- # @param args [Array] arguments of the notification.
95
- def broadcast(msg, *args)
96
- subscribers.each do |a_subscriber|
97
- next unless a_subscriber.respond_to?(msg)
98
- a_subscriber.send(msg, *args)
5
+ class GrammarVisitor
6
+ # Link to the grammar to visit
7
+ attr_reader(:grammar)
8
+
9
+ # List of objects that subscribed to the visit event notification.
10
+ attr_reader(:subscribers)
11
+
12
+ # Build a visitor for the given grammar.
13
+ # @param aGrammar [DynamicGrammar-like] the grammar to visit.
14
+ def initialize(aGrammar)
15
+ @grammar = aGrammar
16
+ @subscribers = []
17
+ end
18
+
19
+ # Add a subscriber for the visit event notification.
20
+ # @param aSubscriber [Object]
21
+ def subscribe(aSubscriber)
22
+ subscribers << aSubscriber
23
+ end
24
+
25
+ # Remove the given object from the subscription list.
26
+ # The object won't be notified of visit events.
27
+ # @param aSubscriber [Object]
28
+ def unsubscribe(aSubscriber)
29
+ subscribers.delete_if { |entry| entry == aSubscriber }
30
+ end
31
+
32
+ # The signal to start the visit.
33
+ def start
34
+ grammar.accept(self)
35
+ end
36
+
37
+ # Visit event. The visitor is about to visit the grammar.
38
+ # @param aGrammar [DynamicGrammar-like] the grammar to visit.
39
+ def start_visit_grammar(aGrammar)
40
+ broadcast(:before_grammar, aGrammar)
41
+ end
42
+
43
+ # Visit event. The visitor is about to visit the given production.
44
+ # @param aProduction [Production] the production to visit.
45
+ def start_visit_production(aProduction)
46
+ broadcast(:before_production, aProduction)
47
+ end
48
+
49
+ # Visit event. The visitor is about to visit the given rhs of production.
50
+ # @param rhs [SymbolSequence] the rhs of a production to visit.
51
+ def start_visit_rhs(rhs)
52
+ broadcast(:before_rhs, rhs)
53
+ end
54
+
55
+ # Visit event. The visitor is visiting the
56
+ # given reference production (= non-terminal symbol).
57
+ # @param aProdRef [ProductionRef] the production reference to visit.
58
+ def visit_prod_ref(aProdRef)
59
+ production = aProdRef.production
60
+ broadcast(:before_non_terminal, production)
61
+ broadcast(:after_non_terminal, production)
62
+ end
63
+
64
+ # Visit event. The visitor is visiting the
65
+ # given terminal symbol.
66
+ # @param aTerminal [Object] the terminal to visit.
67
+ def visit_terminal(aTerminal)
68
+ broadcast(:before_terminal, aTerminal)
69
+ broadcast(:after_terminal, aTerminal)
70
+ end
71
+
72
+ # Visit event. The visitor has completed its visit of the given rhs.
73
+ # @param rhs [SymbolSequence] the rhs of a production to visit.
74
+ def end_visit_rhs(rhs)
75
+ broadcast(:after_rhs, rhs)
76
+ end
77
+
78
+ # Visit event. The visitor has completed its visit of the given production.
79
+ # @param aProduction [Production] the production to visit.
80
+ def end_visit_production(aProduction)
81
+ broadcast(:after_production, aProduction)
82
+ end
83
+
84
+ # Visit event. The visitor has completed the visit of the grammar.
85
+ # @param aGrammar [DynamicGrammar-like] the grammar to visit.
86
+ def end_visit_grammar(aGrammar)
87
+ broadcast(:after_grammar, aGrammar)
88
+ end
89
+
90
+ private
91
+
92
+ # Send a notification to all subscribers.
93
+ # @param msg [Symbol] event to notify
94
+ # @param args [Array] arguments of the notification.
95
+ def broadcast(msg, *args)
96
+ subscribers.each do |a_subscriber|
97
+ next unless a_subscriber.respond_to?(msg)
98
+
99
+ a_subscriber.send(msg, *args)
100
+ end
99
101
  end
100
- end
101
- end # class
102
+ end # class
102
103
  end # module
103
104
 
104
105
  # End of file