lib/rley/parse_forest_visitor.rb in rley-0.3.04 vs lib/rley/parse_forest_visitor.rb in rley-0.3.05

- old
+ new

@@ -1,115 +1,113 @@ -module Rley # This module is used as a namespace - # A visitor class dedicated in the visit of a parse forest. - # It combines the Visitor and Observer patterns. - class ParseForestVisitor - # Link to the parse forest to visit - attr_reader(:pforest) - - # List of objects that subscribed to the visit event notification. - attr_reader(:subscribers) - - # A Hash with pairs of the form: Node => node visit data - attr_reader(:agenda) - - # Indicates the kind of forest traversal to perform: :post_order, :pre-order - attr_reader(:traversal) - - # Build a visitor for the given pforest. - # @param aParseForest [ParseForest] the parse tree to visit. - def initialize(aParseForest, aTraversalStrategy = :post_order) - @pforest = aParseForest - @subscribers = [] - @traversal = aTraversalStrategy - end - - public - - # Add a subscriber for the visit event notifications. - # @param aSubscriber [Object] - def subscribe(aSubscriber) - subscribers << aSubscriber - end - - # Remove the given object from the subscription list. - # The object won't be notified of visit events. - # @param aSubscriber [Object] - def unsubscribe(aSubscriber) - subscribers.delete_if { |entry| entry == aSubscriber } - end - - # The signal to begin the visit of the parse forest. - def start() - pforest.accept(self) - end - - - # Visit event. The visitor is about to visit the pforest. - # @param aParseForest [ParseForest] the pforest to visit. - def start_visit_pforest(aParseForest) - broadcast(:before_pforest, aParseForest) - end - - - # Visit event. The visitor is about to visit the given non terminal node. - # @param aNonTerminalNode [NonTerminalNode] the node to visit. - def visit_nonterminal(aNonTerminalNode) - if @traversal == :post_order - broadcast(:before_non_terminal, aNonTerminalNode) - traverse_children(aNonTerminalNode) - else - traverse_children(aNonTerminalNode) - broadcast(:before_non_terminal, aNonTerminalNode) - end - broadcast(:after_non_terminal, aNonTerminalNode) - end - - # Visit event. The visitor is visiting the - # given terminal node. - # @param aTerminalNode [TerminalNode] the terminal to visit. - def visit_terminal(aTerminalNode) - broadcast(:before_terminal, aTerminalNode) - broadcast(:after_terminal, aTerminalNode) - end - - - # Visit event. The visitor has completed its visit of the given - # non-terminal node. - # @param aNonTerminalNode [NonTerminalNode] the node to visit. - def end_visit_nonterminal(aNonTerminalNode) - broadcast(:after_non_terminal, aNonTerminalNode) - end - - # Visit event. The visitor has completed the visit of the pforest. - # @param aParseForest [ParseForest] the pforest to visit. - def end_visit_pforest(aParseForest) - broadcast(:after_pforest, aParseForest) - end - - private - - # Visit event. The visitor is about to visit the children of a non - # terminal node. - # @param aParentNode [NonTeminalNode] the (non-terminal) parent node. - def traverse_children(aParentNode) - children = aParentNode.children - broadcast(:before_children, aParentNode, children) - - # Let's proceed with the visit of children - children.each { |a_node| a_node.accept(self) } - - broadcast(:after_children, aParentNode, children) - end - - # Send a notification to all subscribers. - # @param msg [Symbol] event to notify - # @param args [Array] arguments of the notification. - def broadcast(msg, *args) - subscribers.each do |a_subscriber| - next unless a_subscriber.respond_to?(msg) - a_subscriber.send(msg, *args) - end - end - end # class -end # module - -# End of file \ No newline at end of file +module Rley # This module is used as a namespace + # A visitor class dedicated in the visit of a parse forest. + # It combines the Visitor and Observer patterns. + class ParseForestVisitor + # Link to the parse forest to visit + attr_reader(:pforest) + + # List of objects that subscribed to the visit event notification. + attr_reader(:subscribers) + + # A Hash with pairs of the form: Node => node visit data + attr_reader(:agenda) + + # Indicates the kind of forest traversal to perform: :post_order, :pre-order + attr_reader(:traversal) + + # Build a visitor for the given pforest. + # @param aParseForest [ParseForest] the parse tree to visit. + def initialize(aParseForest, aTraversalStrategy = :post_order) + @pforest = aParseForest + @subscribers = [] + @traversal = aTraversalStrategy + end + + # Add a subscriber for the visit event notifications. + # @param aSubscriber [Object] + def subscribe(aSubscriber) + subscribers << aSubscriber + end + + # Remove the given object from the subscription list. + # The object won't be notified of visit events. + # @param aSubscriber [Object] + def unsubscribe(aSubscriber) + subscribers.delete_if { |entry| entry == aSubscriber } + end + + # The signal to begin the visit of the parse forest. + def start() + pforest.accept(self) + end + + + # Visit event. The visitor is about to visit the pforest. + # @param aParseForest [ParseForest] the pforest to visit. + def start_visit_pforest(aParseForest) + broadcast(:before_pforest, aParseForest) + end + + + # Visit event. The visitor is about to visit the given non terminal node. + # @param aNonTerminalNode [NonTerminalNode] the node to visit. + def visit_nonterminal(aNonTerminalNode) + if @traversal == :post_order + broadcast(:before_non_terminal, aNonTerminalNode) + traverse_children(aNonTerminalNode) + else + traverse_children(aNonTerminalNode) + broadcast(:before_non_terminal, aNonTerminalNode) + end + broadcast(:after_non_terminal, aNonTerminalNode) + end + + # Visit event. The visitor is visiting the + # given terminal node. + # @param aTerminalNode [TerminalNode] the terminal to visit. + def visit_terminal(aTerminalNode) + broadcast(:before_terminal, aTerminalNode) + broadcast(:after_terminal, aTerminalNode) + end + + + # Visit event. The visitor has completed its visit of the given + # non-terminal node. + # @param aNonTerminalNode [NonTerminalNode] the node to visit. + def end_visit_nonterminal(aNonTerminalNode) + broadcast(:after_non_terminal, aNonTerminalNode) + end + + # Visit event. The visitor has completed the visit of the pforest. + # @param aParseForest [ParseForest] the pforest to visit. + def end_visit_pforest(aParseForest) + broadcast(:after_pforest, aParseForest) + end + + private + + # Visit event. The visitor is about to visit the children of a non + # terminal node. + # @param aParentNode [NonTeminalNode] the (non-terminal) parent node. + def traverse_children(aParentNode) + children = aParentNode.children + broadcast(:before_children, aParentNode, children) + + # Let's proceed with the visit of children + children.each { |a_node| a_node.accept(self) } + + broadcast(:after_children, aParentNode, children) + end + + # Send a notification to all subscribers. + # @param msg [Symbol] event to notify + # @param args [Array] arguments of the notification. + def broadcast(msg, *args) + subscribers.each do |a_subscriber| + next unless a_subscriber.respond_to?(msg) + a_subscriber.send(msg, *args) + end + end + end # class +end # module + +# End of file