sequitur 0.1.18 → 0.1.23

Sign up to get free protection for your applications and to get access to all the features.
@@ -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