Class: BabelBridge::RuleNode
- Inherits:
-
NonTerminalNode
- Object
- Node
- NonTerminalNode
- BabelBridge::RuleNode
- Defined in:
- lib/nodes/rule_node.rb
Overview
subclassed automatically by parser.rule for each unique non-terminal
Instance Attribute Summary
Attributes inherited from Node
#delimiter, #many_delimiter, #match_length, #offset, #parent, #parser, #src
Instance Method Summary collapse
-
#add_match(match, name = nil) ⇒ Object
adds a match with name (optional).
- #add_match_name(match, name) ⇒ Object
-
#attempt_match ⇒ Object
a simple “transaction” - logs the curent number of matches, if the block’s result is false, it discards all new matches.
-
#forward_to(method_name) ⇒ Object
returns where to forward missing methods calls to (safe to override for custom behavior; respond_to? and method_missing will “do the right thing”) returns nil if there is no object to forward to that will respond to the call default: forward to the first match that responds to method_name.
-
#initialize(parent, delimiter_pattern = nil) ⇒ RuleNode
constructor
A new instance of RuleNode.
- #inspect(options = {}) ⇒ Object
-
#match(pattern_element) ⇒ Object
Attempts to match the pattern_element starting at the end of what has already been matched If successful, adds the resulting Node to matches.
- #match_delimiter ⇒ Object
- #match_name_is_poly(name) ⇒ Object
- #match_names ⇒ Object
- #matches_by_name ⇒ Object
-
#method_missing(method_name, *args) ⇒ Object
method_name is a symbol.
- #pop_match ⇒ Object
-
#post_match_processing ⇒ Object
called after matching is done and it was a success returns the node which is actually added to the parse tree.
- #respond_to?(method_name) ⇒ Boolean
Methods inherited from NonTerminalNode
#[], #each, #last_match, #length, #matches, #update_match_length
Methods inherited from Node
#column, #init_line_column, #length, #line, #match_range, #node_init, #node_path, #offset_after_match, #on_matched, #onlychildren_list, #parent_list, #path_string, #relative_class_name, #remaining_src, #text, #to_s, #to_sym
Constructor Details
#initialize(parent, delimiter_pattern = nil) ⇒ RuleNode
Returns a new instance of RuleNode.
12 13 14 15 16 |
# File 'lib/nodes/rule_node.rb', line 12 def initialize(parent, delimiter_pattern = nil) @num_match_attempts = 0 @delimiter_pattern = delimiter_pattern super parent end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args) ⇒ Object
method_name is a symbol
85 86 87 88 89 90 91 92 93 |
# File 'lib/nodes/rule_node.rb', line 85 def method_missing(method_name, *args) #method_name is a symbol return matches_by_name[method_name] if matches_by_name.has_key?(method_name) if f = forward_to(method_name) return f.send(method_name,*args) end raise "#{path_string onlychildren_list}: no methods or named pattern elements match: #{method_name.inspect} on #{self.class} instance" end |
Instance Method Details
#add_match(match, name = nil) ⇒ Object
adds a match with name (optional)
96 97 98 99 100 101 102 103 104 |
# File 'lib/nodes/rule_node.rb', line 96 def add_match(match,name=nil) return unless match return match if match==self add_match_name(super(match),name) update_match_length match end |
#add_match_name(match, name) ⇒ Object
31 32 33 34 35 36 37 38 39 |
# File 'lib/nodes/rule_node.rb', line 31 def add_match_name(match,name) return unless name if current = matches_by_name[name] matches_by_name[name] = MultiMatchesArray.new([current]) if !current.kind_of? MultiMatchesArray matches_by_name[name] << match else matches_by_name[name] = match end end |
#attempt_match ⇒ Object
a simple “transaction” - logs the curent number of matches, if the block’s result is false, it discards all new matches
143 144 145 146 147 148 149 150 151 152 |
# File 'lib/nodes/rule_node.rb', line 143 def attempt_match matches_before = matches.length match_length_before = match_length (yield && match_length > match_length_before).tap do |success| # match_length test returns failure if no progress is made (our source position isn't advanced) unless success @matches = matches[0..matches_before-1] update_match_length end end end |
#forward_to(method_name) ⇒ Object
returns where to forward missing methods calls to (safe to override for custom behavior; respond_to? and method_missing will “do the right thing”) returns nil if there is no object to forward to that will respond to the call default: forward to the first match that responds to method_name
74 75 76 77 |
# File 'lib/nodes/rule_node.rb', line 74 def forward_to(method_name) matches.each {|m| return m if m.respond_to?(method_name)} nil end |
#inspect(options = {}) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/nodes/rule_node.rb', line 45 def inspect(={}) return relative_class_name if matches.length==0 matches = @matches matches=matches.select{|m|!m.many_delimiter} unless [:verbose] matches_inspected = matches.collect{|a|a.inspect()}.compact if matches_inspected.length==0 then nil elsif matches_inspected.length==1 m = matches_inspected[0] ret = "#{relative_class_name} > "+matches_inspected[0] if [:simple] ret = if m["\n"] then m else # just show the first and last nodes in the chain ret.gsub(/( > [A-Z][a-zA-Z0-9:]+ > (\.\.\. > )?)/," > ... > ") end end ret else (["#{relative_class_name}"]+matches_inspected).join("\n").gsub("\n","\n ") end end |
#match(pattern_element) ⇒ Object
Attempts to match the pattern_element starting at the end of what has already been matched If successful, adds the resulting Node to matches. returns nil on if pattern_element wasn’t matched; non-nil if it was skipped or matched
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/nodes/rule_node.rb', line 113 def match(pattern_element) @num_match_attempts += 1 return :no_pattern_element unless pattern_element return :skipped if pattern_element.delimiter && ( if last_match last_match.delimiter # don't match two delimiters in a row else @num_match_attempts > 1 # don't match a delimiter as the first element unless this is the first match attempt end ) if result = pattern_element.parse(self) add_match result, pattern_element.name # success, but don't keep EmptyNodes end end |
#match_delimiter ⇒ Object
130 131 132 |
# File 'lib/nodes/rule_node.rb', line 130 def match_delimiter match @delimiter_pattern end |
#match_name_is_poly(name) ⇒ Object
22 23 24 25 26 27 28 29 |
# File 'lib/nodes/rule_node.rb', line 22 def match_name_is_poly(name) return unless name if current = matches_by_name[name] matches_by_name[name] = MultiMatchesArray.new([current]) if !current.kind_of? MultiMatchesArray else matches_by_name[name] = MultiMatchesArray.new end end |
#match_names ⇒ Object
18 19 20 |
# File 'lib/nodes/rule_node.rb', line 18 def match_names @match_names ||= [] end |
#matches_by_name ⇒ Object
41 42 43 |
# File 'lib/nodes/rule_node.rb', line 41 def matches_by_name @matches_by_name||={} end |
#pop_match ⇒ Object
106 107 108 |
# File 'lib/nodes/rule_node.rb', line 106 def pop_match matches.pop.tap {update_match_length} end |
#post_match_processing ⇒ Object
called after matching is done and it was a success returns the node which is actually added to the parse tree
136 137 138 139 |
# File 'lib/nodes/rule_node.rb', line 136 def post_match_processing on_matched self end |
#respond_to?(method_name) ⇒ Boolean
79 80 81 82 83 |
# File 'lib/nodes/rule_node.rb', line 79 def respond_to?(method_name) super || matches_by_name[method_name] || forward_to(method_name) end |