Module: UnifiedRuby

Included in:
Unifier
Defined in:
lib/unified_ruby.rb

Instance Method Summary collapse

Instance Method Details

#rewrite_bmethod(exp) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/unified_ruby.rb', line 5

def rewrite_bmethod(exp)
  exp[0] = :scope

  args =
    if exp.masgn and exp.masgn.dasgn_curr then
      arg = exp.masgn(true).dasgn_curr(true).sexp_body
      raise "nope: #{arg.size}" unless arg.size == 1
      s(:args, :"*#{arg.last}")
    else
      args = exp.dasgn_curr(true)
      if args then
        s(:args, *args.sexp_body)
      else
        exp.delete_at 1 # nil
        s(:args)
      end
    end

  exp = s(:scope, s(:block, *exp.sexp_body)) unless exp.block
  exp.block.insert 1, args
  exp.find_and_replace_all(:dvar, :lvar)

  exp
end

#rewrite_call(exp) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/unified_ruby.rb', line 30

def rewrite_call(exp)
  args = exp.last
  case args
  when nil
    exp.pop
  when Array
    case args.first
    when :array, :arglist then
      args[0] = :arglist
    when :argscat, :splat then
      # do nothing
    else
      raise "unknown type in call #{args.first.inspect} in #{exp.inspect}"
    end
    return exp
  end

  exp << s(:arglist)

  exp
end

#rewrite_defn(exp) ⇒ Object

:defn is one of the most complex of all the ASTs in ruby. We do one of 3 different translations:

1) From:

s(:defn, :name, s(:scope, s(:block, s(:args, ...), ...)))
s(:defn, :name, s(:bmethod, s(:masgn, s(:dasgn_curr, :args)), s(:block, ...)))
s(:defn, :name, s(:fbody, s(:bmethod, s(:masgn, s(:dasgn_curr, :splat)), s(:block, ...))))

to:

s(:defn, :name, s(:args, ...), s(:scope, s:(block, ...)))

2) From:

s(:defn, :writer=, s(:attrset, :@name))

to:

s(:defn, :writer=, s(:args), s(:attrset, :@name))

3) From:

s(:defn, :reader, s(:ivar, :@name))

to:

s(:defn, :reader, s(:args), s(:ivar, :@name))


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/unified_ruby.rb', line 83

def rewrite_defn(exp)
  weirdo = exp.ivar || exp.attrset

  fbody = exp.fbody(true)
  exp.push(fbody.scope) if fbody

  args = exp.scope.block.args(true) unless weirdo
  exp.insert 2, args if args

  # move block_arg up and in
  block_arg = exp.scope.block.block_arg(true) rescue nil
  exp.args << block_arg if block_arg

  # patch up attr_accessor methods
  exp.insert 2, s(:args) if weirdo

  exp
end

#rewrite_defs(exp) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/unified_ruby.rb', line 102

def rewrite_defs(exp)
  receiver = exp.delete_at 1

  # TODO: I think this would be better as rewrite_scope, but that breaks others
  exp = s(exp.shift, exp.shift,
          s(:scope,
            s(:block, exp.scope.args))) if exp.scope.args

  result = rewrite_defn(exp)
  result.insert 1, receiver

  result
end

#rewrite_dmethod(exp) ⇒ Object



116
117
118
119
120
# File 'lib/unified_ruby.rb', line 116

def rewrite_dmethod(exp)
  exp.shift # type
  exp.shift # dmethod name
  exp.shift # scope / block / body
end

#rewrite_fcall(exp) ⇒ Object



122
123
124
125
126
127
128
# File 'lib/unified_ruby.rb', line 122

def rewrite_fcall(exp)
  exp[0] = :call
  exp.insert 1, nil
  exp.push nil if exp.size <= 3

  rewrite_call(exp)
end

#rewrite_resbody(exp) ⇒ Object

TODO: clean up and move to unified



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/unified_ruby.rb', line 130

def rewrite_resbody(exp) # TODO: clean up and move to unified
  result = s()

  code = result
  while exp and exp.first == :resbody do
    code << exp.shift
    list = exp.shift || s(:array)
    body = exp.empty? ? nil : exp.shift
    exp  = exp.empty? ? nil : exp.shift

    # code may be nil, :lasgn, or :block
    case body.first
    when nil then
      # do nothing
    when :lasgn then
      # TODO: check that it is assigning $!
      list << body
      body = nil
    when :block then
      # TODO: check that it is assigning $!
      list << body.delete_at(1) if body[1].first == :lasgn
    else
      # do nothing (expression form)
    end if body

    code << list << body
    if exp then
      code = s()
      result << code
    end
  end

  if $DEBUG or $TESTING then
    structure = result.structure
    raise "result structure wrong: #{structure[0..1].inspect}" unless
      structure.flatten[0] == :resbody
    raise "result structure wrong: #{structure[0..1].inspect}" unless
      s(:array, :splat, :argscat).include? structure.flatten[1]
    raise "result body wrong: #{structure[2].inspect}" unless
      structure[2].nil? or not structure[2].empty?
  end

  result
end

#rewrite_vcall(exp) ⇒ Object



175
176
177
178
# File 'lib/unified_ruby.rb', line 175

def rewrite_vcall(exp)
  exp.push nil
  rewrite_fcall(exp)
end