class Rley::ParseForestVisitor
A visitor class dedicated in the visit of a parse forest. It combines the Visitor and Observer patterns.
Attributes
@return [Array<SPPF::CompositeNode, Integer>]
Stack of [node, path signature]
path signature: an integer value that represents the set of edges used in traversal
@return [Hash{SPPF::CompositeNode, Array<Integer>}]
Keep trace from which path(s) a given node was accessed
@return [SPPF::ParseForest] Link to the parse forest to visit
@return [Enumerator] Enumerator that generates a sequence of prime numbers
@return [Array<Object>]
List of objects that subscribed to the visit event notification.
Public Class Methods
Source
# File lib/rley/parse_forest_visitor.rb, line 49 def initialize(aParseForest) @pforest = aParseForest @subscribers = [] @prime_enum = Prime.instance.each @legs = [] @node_accesses = Hash.new { |h, key| h[key] = [] } end
Build a visitor for the given pforest. @param aParseForest [SPPF::ParseForest] the parse tree to visit.
Public Instance Methods
Source
# File lib/rley/parse_forest_visitor.rb, line 131 def end_visit_pforest(aParseForest) broadcast(:after_pforest, aParseForest) end
Visit event. The visitor has completed the visit of the pforest. @param aParseForest [ParseForest] the pforest to visit.
Source
# File lib/rley/parse_forest_visitor.rb, line 71 def start pforest.accept(self) end
The signal to begin the visit of the parse forest.
Source
# File lib/rley/parse_forest_visitor.rb, line 77 def start_visit_pforest(aParseForest) broadcast(:before_pforest, aParseForest) end
Visit event. The visitor is about to visit the pforest. @param aParseForest [ParseForest] the pforest to visit.
Source
# File lib/rley/parse_forest_visitor.rb, line 59 def subscribe(aSubscriber) subscribers << aSubscriber end
Add a subscriber for the visit event notifications. @param aSubscriber [Object]
Source
# File lib/rley/parse_forest_visitor.rb, line 66 def unsubscribe(aSubscriber) subscribers.delete_if { |entry| entry == aSubscriber } end
Remove the given object from the subscription list. The object won’t be notified of visit events. @param aSubscriber [Object]
Source
# File lib/rley/parse_forest_visitor.rb, line 96 def visit_alternative(alternativeNd) broadcast(:before_alternative, alternativeNd) unless alternativeNd.signature_exist? alternativeNd.add_edge_signatures(prime_enum) end traverse_children(alternativeNd) broadcast(:after_alternative, alternativeNd) end
TODO: control the logic of this method. Visit event. The visitor is visiting the given alternative node. @param alternativeNd [AlternativeNode] the alternative node to visit.
Source
# File lib/rley/parse_forest_visitor.rb, line 117 def visit_epsilon(anEpsilonNode) broadcast(:before_epsilon, anEpsilonNode) broadcast(:after_epsilon, anEpsilonNode) end
Visit event. The visitor is visiting the given epsilon node. @param anEpsilonNode [EpsilonNode] the terminal to visit.
Source
# File lib/rley/parse_forest_visitor.rb, line 83 def visit_nonterminal(nonTerminalNd) broadcast(:before_non_terminal, nonTerminalNd) unless nonTerminalNd.signature_exist? nonTerminalNd.add_edge_signatures(prime_enum) end traverse_children(nonTerminalNd) broadcast(:after_non_terminal, nonTerminalNd) end
Visit event. The visitor is about to visit the given non terminal node. @param nonTerminalNd [NonTerminalNode] the node to visit.
Source
# File lib/rley/parse_forest_visitor.rb, line 109 def visit_terminal(aTerminalNode) broadcast(:before_terminal, aTerminalNode) broadcast(:after_terminal, aTerminalNode) end
Visit event. The visitor is visiting the given terminal node. @param aTerminalNode [TerminalNode] the terminal to visit.
Private Instance Methods
Source
# File lib/rley/parse_forest_visitor.rb, line 169 def broadcast(msg, *args) subscribers.each do |subscr| next unless subscr.respond_to?(msg) || subscr.respond_to?(:accept_all) subscr.send(msg, *args) end end
Send a notification to all subscribers. @param msg [Symbol] event to notify @param args [Array] arguments of the notification.
Source
# File lib/rley/parse_forest_visitor.rb, line 191 def pop_node return if legs.empty? legs.pop end
Source
# File lib/rley/parse_forest_visitor.rb, line 177 def push_node(aCompositeNode, anEdgeSignature) if legs.empty? legs << [aCompositeNode, anEdgeSignature] else # @type var path_signature : Integer path_signature = legs.last[-1] if (path_signature % anEdgeSignature).zero? legs << [aCompositeNode, path_signature] else legs << [aCompositeNode, path_signature * anEdgeSignature] end end end
Source
# File lib/rley/parse_forest_visitor.rb, line 140 def traverse_children(aParentNode) children = aParentNode.children broadcast(:before_subnodes, aParentNode, children) # Let's proceed with the visit of children children.each_with_index do |a_node, i| edge_sign = aParentNode.signatures[i] if a_node.is_a?(SPPF::CompositeNode) push_node(a_node, edge_sign) access_paths = node_accesses[a_node] # @type var last_path : Integer last_path = legs.last[-1] path_reused = access_paths.include?(last_path) unless path_reused node_accesses[a_node].push(last_path) a_node.accept(self) end pop_node else a_node.accept(self) end end broadcast(:after_subnodes, aParentNode, children) end
Visit event. The visitor is about to visit the children of a non terminal node. @param aParentNode [NonTeminalNode] the (non-terminal) parent node.