Class: Matcher

Inherits:
Object show all
Defined in:
lib/ytljit/matcher.rb

Instance Method Summary collapse

Constructor Details

#initializeMatcher

Returns a new instance of Matcher.



62
63
64
65
66
# File 'lib/ytljit/matcher.rb', line 62

def initialize
  @cache = {}
  @code = nil
  @pattern = []
end

Instance Method Details

#code_gen(info) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/ytljit/matcher.rb', line 162

def code_gen(info)
  ct = {}
  info.each do |carr, val|
    cursor = ct
    carr.each do |cele|
      cursor[cele] ||= {}
      cursor = cursor[cele]
    end
    cursor[nil] = val
  end

  code = <<-EOS
  org_self = self
  ObjectSpace._id2ref(#{self.object_id}).instance_eval do 
    #{cond_gen(ct, 0)} 
  end
EOS
  RubyVM::InstructionSequence.compile(code)
end

#compileObject



82
83
84
85
86
87
88
89
90
# File 'lib/ytljit/matcher.rb', line 82

def compile
  info = {}
  @pattern.each do |pat|
    env = {}
    cond = compile_aux(pat[0], [], env, [])[0]
    info[cond] = [env, pat[1]]
  end
  @code = code_gen(info)
end

#compile_aux(pat, stack, env, cond) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/ytljit/matcher.rb', line 92

def compile_aux(pat, stack, env, cond)
  status = :normal
  case pat
  when Array
    if pat[0].is_a?(Class) then
      cond.push "(#{get_patref(stack)}.is_a?(#{pat[0]}))"
      env[pat[1]] = "#{get_patref(stack)}"
    else
      cond.push "(#{get_patref(stack)}.is_a?(Array))"
      stack.push 0
      pat.each_with_index do |ele, i|
        stack[-1] = i
        cond, st = compile_aux(ele, stack, env, cond)
        if st == :return then
          stack.pop
          return [cond, status]
        end
      end
      stack[-1] = pat.size
      cond.push "(#{get_patref(stack)} == nil)"
      stack.pop
    end
    
  when Symbol
    patstr = pat.to_s
    if patstr[0] == '_' then
      npat = patstr[1..-1].to_sym
      if env[npat] then
        cond.push "#{get_patref_rest(stack)} == #{env[npat]}"
      else
        env[npat] = get_patref_rest(stack)
      end
      status = :return
    else
      if env[pat] then
        cond.push "(#{get_patref(stack)}.is_a?(Symbol) or #{get_patref(stack)} == #{env[pat]})"
      else
        env[pat] = get_patref(stack).to_s
      end
    end

  when QuotedObj
    cond.push "(#{get_patref(stack)} == #{pat.obj.inspect})"

  else
    cond.push "(#{get_patref(stack)} == #{pat})"
  end

  return [cond, status]
end

#cond_gen(tr, level) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/ytljit/matcher.rb', line 182

def cond_gen(tr, level)
  code = ""
  tr.each do |cond, nxt|
    if cond then
      code << "if #{cond} then \n"
      code << cond_gen(nxt, level + 1)
      code << "end\n"
    end
  end
  if tr[nil] then
    code << "#{exec_gen(tr[nil])} \n"
  end
  code
end

#exec_gen(para) ⇒ Object



197
198
199
200
201
202
203
204
205
206
# File 'lib/ytljit/matcher.rb', line 197

def exec_gen(para)
  hash = "{"
  para[0].each do |key, value|
    hash << ":#{key} => #{value},"
  end
  hash << "}"
  
  proc = para[1]
  "break ObjectSpace._id2ref(#{proc.object_id}).call(#{hash})"
end

#get_patref(stack) ⇒ Object



143
144
145
146
147
148
149
# File 'lib/ytljit/matcher.rb', line 143

def get_patref(stack)
  code = "@src"
  stack.each do |n|
    code += "[#{n}]"
  end
  code
end

#get_patref_rest(stack) ⇒ Object



151
152
153
154
155
156
157
158
159
160
# File 'lib/ytljit/matcher.rb', line 151

def get_patref_rest(stack)
  code = "@src"
  top = stack.pop
  stack.each do |n|
    code += "[#{n}]"
  end
  code += "[#{top}.. -1]"
  stack.push top
  code
end

#match(src) ⇒ Object



68
69
70
71
72
73
74
# File 'lib/ytljit/matcher.rb', line 68

def match(src)
  unless @code
    compile
  end
  @src = src
  @code.eval
end

#pattern(pat, &block) ⇒ Object



76
77
78
79
80
# File 'lib/ytljit/matcher.rb', line 76

def pattern(pat, &block)
  unless @code
    @pattern.push [pat, block]
  end
end