| 1 | # snarfed from redsix. much can probably be discarded, |
|---|
| 2 | # and much is probably non-spec, but we'll get to both in a bit. |
|---|
| 3 | |
|---|
| 4 | module MatchDescribe |
|---|
| 5 | def match_describe(seen=nil) |
|---|
| 6 | seen ||= {} |
|---|
| 7 | return ("LOOP***"+match_describe_name) if seen.member?(self.object_id); seen[self.object_id] = true |
|---|
| 8 | spsp = ' '.force_encoding('utf-8') |
|---|
| 9 | indent = lambda{|s| s ? s.gsub(/(?m)^(?!\Z)/,spsp) : '*nil*' } |
|---|
| 10 | indent_except_top = lambda{|s| s ? s.gsub(/(?m)^(?!\Z)/,spsp).sub(/^ /,'') : '*nil*' } |
|---|
| 11 | n = match_describe_name |
|---|
| 12 | b = as_b ? 'true' : 'false' |
|---|
| 13 | s = "'"+indent_except_top.call(as_s).gsub(/([\\'])/){|w|"\\#{w}"}+"'" |
|---|
| 14 | a = as_a.map{|m| "\n"+indent.call(m.match_describe(seen))+"," }.join("") |
|---|
| 15 | a += "\n" if a != "" |
|---|
| 16 | h = as_h.map{|k,v| |
|---|
| 17 | vs = if v.instance_of?(Array) and not v.empty? |
|---|
| 18 | "[\n" + indent.call(v.map{|e| (e.respond_to?(:match_describe) ? |
|---|
| 19 | e.match_describe(seen) : |
|---|
| 20 | e.inspect)}.join(",\n"))+"\n]" |
|---|
| 21 | else |
|---|
| 22 | (v.respond_to?(:match_describe) ? |
|---|
| 23 | v.match_describe(seen) : |
|---|
| 24 | v.inspect) |
|---|
| 25 | end |
|---|
| 26 | "\n #{k} => #{indent_except_top.call(vs)}," |
|---|
| 27 | }.join("") |
|---|
| 28 | h += "\n" if h != "" |
|---|
| 29 | f = match_beg |
|---|
| 30 | t = match_end |
|---|
| 31 | "#{n}<#{b},#{s},#{f}-#{t},[#{a}],{#{h}}>" |
|---|
| 32 | end |
|---|
| 33 | def match_describe_name() |
|---|
| 34 | "#{self.class}:#{object_id.to_s(36)}" |
|---|
| 35 | # "#{self.class}" |
|---|
| 36 | end |
|---|
| 37 | end |
|---|
| 38 | class Match |
|---|
| 39 | attr_accessor :on_str,:from,:to,:bool,:hash |
|---|
| 40 | attr_writer :str |
|---|
| 41 | attr_accessor :rule |
|---|
| 42 | def initialize(on_str,from,to,bool,hash,str,rule=nil) |
|---|
| 43 | @on_str,@from,@to,@bool,@hash,@str,@rule=on_str,from,to,bool,hash,str,rule |
|---|
| 44 | end |
|---|
| 45 | def self.new_from(on_str,from=0,to=nil) |
|---|
| 46 | self.new(on_str,from,to,true,{},nil) |
|---|
| 47 | end |
|---|
| 48 | def skim_state_copy |
|---|
| 49 | self.class.new(@on_str,@from,@to,@bool,@hash.skim_state_copy,@str,@rule) |
|---|
| 50 | end |
|---|
| 51 | def str(to=nil) |
|---|
| 52 | return "ERROR:from is nil" if not @from; |
|---|
| 53 | @str || @on_str.slice(@from,(@to||to)-@from) |
|---|
| 54 | end |
|---|
| 55 | def close!(to) |
|---|
| 56 | if @from # otherwise already .failed! |
|---|
| 57 | @to = to |
|---|
| 58 | @str = @on_str.slice(@from,@to-@from) if @from |
|---|
| 59 | end |
|---|
| 60 | self |
|---|
| 61 | end |
|---|
| 62 | def failed! |
|---|
| 63 | @bool,@str,@hash,@from,@to = false,'',{},nil,nil |
|---|
| 64 | self |
|---|
| 65 | end |
|---|
| 66 | def closer_proc |
|---|
| 67 | SkimProc.new{|s,c| self.close!(s.pos); c.cont0(s)} |
|---|
| 68 | end |
|---|
| 69 | |
|---|
| 70 | include MatchDescribe |
|---|
| 71 | def as_b; @bool end; def as_s; str end; def as_a; [] end; def as_h; @hash end |
|---|
| 72 | def match_beg; @from end; def match_end; @to end |
|---|
| 73 | def match_describe_name; "#{super}:#{rule ? rule : 'nil'}" end |
|---|
| 74 | #def inspect; match_describe end |
|---|
| 75 | #def inspect; STDERR.print "inspection refused - yaml debugging test\n" end |
|---|
| 76 | end |
|---|
| 77 | |
|---|
| 78 | |
|---|
| 79 | class Match |
|---|
| 80 | def [](k) |
|---|
| 81 | #raise "Invalid Match hash key: #{k}\n#{self}\n" if not @hash.key?(k) |
|---|
| 82 | @hash[k] |
|---|
| 83 | end |
|---|
| 84 | def []=(k,v); @hash[k] = v; end |
|---|
| 85 | def key?(k); @hash.key? k; end |
|---|
| 86 | def method_missing(m,*a,&b) |
|---|
| 87 | if @hash.key?(m) |
|---|
| 88 | @hash[m] |
|---|
| 89 | else |
|---|
| 90 | super |
|---|
| 91 | end |
|---|
| 92 | end |
|---|
| 93 | |
|---|
| 94 | def perl; inspect; end #R XXX hack |
|---|
| 95 | def prepare_for_yaml_dump |
|---|
| 96 | @str = str |
|---|
| 97 | #remove_instance_variable(:@str) |
|---|
| 98 | remove_instance_variable(:@on_str) |
|---|
| 99 | scrub = proc{|x| |
|---|
| 100 | if x.respond_to?(:prepare_for_yaml_dump) |
|---|
| 101 | x.prepare_for_yaml_dump |
|---|
| 102 | elsif x.is_a?(Array) |
|---|
| 103 | x.each{|o2| scrub.call(o2)} |
|---|
| 104 | elsif x.is_a?(Hash) |
|---|
| 105 | x.values.each{|o2| scrub.call(o2)} |
|---|
| 106 | end |
|---|
| 107 | } |
|---|
| 108 | instance_variables.each{|v| |
|---|
| 109 | o = instance_variable_get(v) |
|---|
| 110 | scrub.call(o) |
|---|
| 111 | } |
|---|
| 112 | end |
|---|
| 113 | end |
|---|
| 114 | |
|---|
| 115 | |
|---|
| 116 | class Array |
|---|
| 117 | def to_dump0; '['+map{|e| e.to_dump0}.join(",")+']'; end |
|---|
| 118 | end |
|---|
| 119 | class Hash |
|---|
| 120 | def to_dump0; '{'+map{|k,v| k.to_s+' => '+v.to_dump0}.join(",")+'}' end |
|---|
| 121 | end |
|---|
| 122 | class String |
|---|
| 123 | def to_dump0; inspect.gsub(/([$@%])/){|m|'\\'+m[0]} end |
|---|
| 124 | end |
|---|
| 125 | class Symbol |
|---|
| 126 | def to_dump0; to_s.inspect end |
|---|
| 127 | end |
|---|
| 128 | class FalseClass |
|---|
| 129 | def to_dump0; '0' end |
|---|
| 130 | end |
|---|
| 131 | class Fixnum |
|---|
| 132 | def to_dump0; inspect end |
|---|
| 133 | end |
|---|
| 134 | class Match |
|---|
| 135 | def to_dump0 |
|---|
| 136 | b = as_b ? '1' : '0' |
|---|
| 137 | s = "'"+str.gsub(/([\\'])/){|w|"\\#{w}"}+"'" |
|---|
| 138 | #a = as_a.map{|e| "\n"+e.to_dump0+"," }.join("") |
|---|
| 139 | #a += "\n" if a != "" |
|---|
| 140 | h = as_h.map{|k,v| |
|---|
| 141 | vs = v.to_dump0 |
|---|
| 142 | "\n #{k} => #{vs}," |
|---|
| 143 | }.join("") |
|---|
| 144 | h += "\n" if h != "" |
|---|
| 145 | f = match_beg |
|---|
| 146 | t = match_end |
|---|
| 147 | r = @rule.to_s.inspect |
|---|
| 148 | "match(#{r},#{s},#{f},#{t},{#{h}})" |
|---|
| 149 | end |
|---|
| 150 | end |
|---|
| 151 | |
|---|
| 152 | class Array |
|---|
| 153 | def to_dump1; '(array '+map{|e| e.to_dump1}.join(" ")+')'; end |
|---|
| 154 | end |
|---|
| 155 | class Hash |
|---|
| 156 | def to_dump1; '(hash '+map{|k,v| '"'+k.to_s+'" '+v.to_dump1}.join(" ")+')' end |
|---|
| 157 | end |
|---|
| 158 | class String |
|---|
| 159 | def to_dump1; '"'+gsub(/([\\"])/){|w|"\\#{w}"}+'"' end |
|---|
| 160 | end |
|---|
| 161 | class Symbol |
|---|
| 162 | def to_dump1; to_s.inspect end |
|---|
| 163 | end |
|---|
| 164 | class FalseClass |
|---|
| 165 | def to_dump1; ':false' end |
|---|
| 166 | end |
|---|
| 167 | class Fixnum |
|---|
| 168 | def to_dump1; inspect end |
|---|
| 169 | end |
|---|
| 170 | class Match |
|---|
| 171 | def to_dump1 |
|---|
| 172 | b = as_b ? '1' : '0' |
|---|
| 173 | s = str.to_dump1 |
|---|
| 174 | h = as_h.map{|k,v| |
|---|
| 175 | vs = v.to_dump1 |
|---|
| 176 | "\n \"#{k}\" #{vs} " |
|---|
| 177 | }.join("") |
|---|
| 178 | h += "\n" if h != "" |
|---|
| 179 | f = match_beg |
|---|
| 180 | t = match_end |
|---|
| 181 | r = @rule.to_s.inspect |
|---|
| 182 | "(match #{r} #{s} #{f} #{t} (hash #{h}))" |
|---|
| 183 | end |
|---|
| 184 | end |
|---|