thor 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.markdown +61 -0
- data/Rakefile +41 -0
- data/bin/thor +327 -0
- data/lib/getopt.rb +238 -0
- data/lib/thor.rb +131 -0
- data/lib/thor/tasks.rb +76 -0
- data/lib/vendor/ruby2ruby.rb +1090 -0
- data/lib/vendor/sexp.rb +278 -0
- data/lib/vendor/sexp_processor.rb +336 -0
- data/lib/vendor/unified_ruby.rb +196 -0
- metadata +66 -0
data/lib/getopt.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
# The last time the Getopt gem was modified was August 2007, so it's safe to vendor (it does everything we need)
|
2
|
+
|
3
|
+
module Getopt
|
4
|
+
|
5
|
+
REQUIRED = 0
|
6
|
+
BOOLEAN = 1
|
7
|
+
OPTIONAL = 2
|
8
|
+
INCREMENT = 3
|
9
|
+
NEGATABLE = 4
|
10
|
+
NUMERIC = 5
|
11
|
+
|
12
|
+
class Long
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
VERSION = '1.3.6'
|
16
|
+
|
17
|
+
# Takes an array of switches. Each array consists of up to three
|
18
|
+
# elements that indicate the name and type of switch. Returns a hash
|
19
|
+
# containing each switch name, minus the '-', as a key. The value
|
20
|
+
# for each key depends on the type of switch and/or the value provided
|
21
|
+
# by the user.
|
22
|
+
#
|
23
|
+
# The long switch _must_ be provided. The short switch defaults to the
|
24
|
+
# first letter of the short switch. The default type is BOOLEAN.
|
25
|
+
#
|
26
|
+
# Example:
|
27
|
+
#
|
28
|
+
# opts = Getopt::Long.getopts(
|
29
|
+
# ["--debug"],
|
30
|
+
# ["--verbose", "-v"],
|
31
|
+
# ["--level", "-l", NUMERIC]
|
32
|
+
# )
|
33
|
+
#
|
34
|
+
# See the README file for more information.
|
35
|
+
#
|
36
|
+
def self.getopts(*switches)
|
37
|
+
if switches.empty?
|
38
|
+
raise ArgumentError, "no switches provided"
|
39
|
+
end
|
40
|
+
|
41
|
+
hash = {} # Hash returned to user
|
42
|
+
valid = [] # Tracks valid switches
|
43
|
+
types = {} # Tracks argument types
|
44
|
+
syns = {} # Tracks long and short arguments, or multiple shorts
|
45
|
+
|
46
|
+
# If a string is passed, split it and convert it to an array of arrays
|
47
|
+
if switches.first.kind_of?(String)
|
48
|
+
switches = switches.join.split
|
49
|
+
switches.map!{ |switch| switch = [switch] }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set our list of valid switches, and proper types for each switch
|
53
|
+
switches.each{ |switch|
|
54
|
+
valid.push(switch[0]) # Set valid long switches
|
55
|
+
|
56
|
+
# Set type for long switch, default to BOOLEAN.
|
57
|
+
if switch[1].kind_of?(Fixnum)
|
58
|
+
switch[2] = switch[1]
|
59
|
+
types[switch[0]] = switch[2]
|
60
|
+
switch[1] = switch[0][1..2]
|
61
|
+
else
|
62
|
+
switch[2] ||= BOOLEAN
|
63
|
+
types[switch[0]] = switch[2]
|
64
|
+
switch[1] ||= switch[0][1..2]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Create synonym hash. Default to first char of long switch for
|
68
|
+
# short switch, e.g. "--verbose" creates a "-v" synonym. The same
|
69
|
+
# synonym can only be used once - first one wins.
|
70
|
+
syns[switch[0]] = switch[1] unless syns[switch[1]]
|
71
|
+
syns[switch[1]] = switch[0] unless syns[switch[1]]
|
72
|
+
|
73
|
+
switch[1].each{ |char|
|
74
|
+
types[char] = switch[2] # Set type for short switch
|
75
|
+
valid.push(char) # Set valid short switches
|
76
|
+
}
|
77
|
+
|
78
|
+
if ARGV.empty? && switch[2] == REQUIRED
|
79
|
+
raise Error, "no value provided for required argument '#{switch[0]}'"
|
80
|
+
end
|
81
|
+
}
|
82
|
+
|
83
|
+
re_long = /^(--\w+[-\w+]*)?$/
|
84
|
+
re_short = /^(-\w)$/
|
85
|
+
re_long_eq = /^(--\w+[-\w+]*)?=(.*?)$|(-\w?)=(.*?)$/
|
86
|
+
re_short_sq = /^(-\w)(\S+?)$/
|
87
|
+
|
88
|
+
ARGV.each_with_index{ |opt, index|
|
89
|
+
|
90
|
+
# Allow either -x -v or -xv style for single char args
|
91
|
+
if re_short_sq.match(opt)
|
92
|
+
chars = opt.split("")[1..-1].map{ |s| s = "-#{s}" }
|
93
|
+
|
94
|
+
chars.each_with_index{ |char, i|
|
95
|
+
unless valid.include?(char)
|
96
|
+
raise Error, "invalid switch '#{char}'"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Grab the next arg if the switch takes a required arg
|
100
|
+
if types[char] == REQUIRED
|
101
|
+
# Deal with a argument squished up against switch
|
102
|
+
if chars[i+1]
|
103
|
+
arg = chars[i+1..-1].join.tr("-","")
|
104
|
+
ARGV.push(char, arg)
|
105
|
+
break
|
106
|
+
else
|
107
|
+
arg = ARGV.delete_at(index+1)
|
108
|
+
if arg.nil? || valid.include?(arg) # Minor cheat here
|
109
|
+
err = "no value provided for required argument '#{char}'"
|
110
|
+
raise Error, err
|
111
|
+
end
|
112
|
+
ARGV.push(char, arg)
|
113
|
+
end
|
114
|
+
elsif types[char] == OPTIONAL
|
115
|
+
if chars[i+1] && !valid.include?(chars[i+1])
|
116
|
+
arg = chars[i+1..-1].join.tr("-","")
|
117
|
+
ARGV.push(char, arg)
|
118
|
+
break
|
119
|
+
elsif
|
120
|
+
if ARGV[index+1] && !valid.include?(ARGV[index+1])
|
121
|
+
arg = ARGV.delete_at(index+1)
|
122
|
+
ARGV.push(char, arg)
|
123
|
+
end
|
124
|
+
else
|
125
|
+
ARGV.push(char)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
ARGV.push(char)
|
129
|
+
end
|
130
|
+
}
|
131
|
+
next
|
132
|
+
end
|
133
|
+
|
134
|
+
if match = re_long.match(opt) || match = re_short.match(opt)
|
135
|
+
switch = match.captures.first
|
136
|
+
end
|
137
|
+
|
138
|
+
if match = re_long_eq.match(opt)
|
139
|
+
switch, value = match.captures.compact
|
140
|
+
ARGV.push(switch, value)
|
141
|
+
next
|
142
|
+
end
|
143
|
+
|
144
|
+
# Make sure that all the switches are valid. If 'switch' isn't
|
145
|
+
# defined at this point, it means an option was passed without
|
146
|
+
# a preceding switch, e.g. --option foo bar.
|
147
|
+
unless valid.include?(switch)
|
148
|
+
switch ||= opt
|
149
|
+
raise Error, "invalid switch '#{switch}'"
|
150
|
+
end
|
151
|
+
|
152
|
+
# Required arguments
|
153
|
+
if types[switch] == REQUIRED
|
154
|
+
nextval = ARGV[index+1]
|
155
|
+
|
156
|
+
# Make sure there's a value for mandatory arguments
|
157
|
+
if nextval.nil?
|
158
|
+
err = "no value provided for required argument '#{switch}'"
|
159
|
+
raise Error, err
|
160
|
+
end
|
161
|
+
|
162
|
+
# If there is a value, make sure it's not another switch
|
163
|
+
if valid.include?(nextval)
|
164
|
+
err = "cannot pass switch '#{nextval}' as an argument"
|
165
|
+
raise Error, err
|
166
|
+
end
|
167
|
+
|
168
|
+
# If the same option appears more than once, put the values
|
169
|
+
# in array.
|
170
|
+
if hash[switch]
|
171
|
+
hash[switch] = [hash[switch], nextval].flatten
|
172
|
+
else
|
173
|
+
hash[switch] = nextval
|
174
|
+
end
|
175
|
+
ARGV.delete_at(index+1)
|
176
|
+
end
|
177
|
+
|
178
|
+
# For boolean arguments set the switch's value to true.
|
179
|
+
if types[switch] == BOOLEAN
|
180
|
+
if hash.has_key?(switch)
|
181
|
+
raise Error, "boolean switch already set"
|
182
|
+
end
|
183
|
+
hash[switch] = true
|
184
|
+
end
|
185
|
+
|
186
|
+
# For increment arguments, set the switch's value to 0, or
|
187
|
+
# increment it by one if it already exists.
|
188
|
+
if types[switch] == INCREMENT
|
189
|
+
if hash.has_key?(switch)
|
190
|
+
hash[switch] += 1
|
191
|
+
else
|
192
|
+
hash[switch] = 1
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# For optional argument, there may be an argument. If so, it
|
197
|
+
# cannot be another switch. If not, it is set to true.
|
198
|
+
if types[switch] == OPTIONAL
|
199
|
+
nextval = ARGV[index+1]
|
200
|
+
if valid.include?(nextval)
|
201
|
+
hash[switch] = true
|
202
|
+
else
|
203
|
+
hash[switch] = nextval
|
204
|
+
ARGV.delete_at(index+1)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
}
|
208
|
+
|
209
|
+
# Set synonymous switches to the same value, e.g. if -t is a synonym
|
210
|
+
# for --test, and the user passes "--test", then set "-t" to the same
|
211
|
+
# value that "--test" was set to.
|
212
|
+
#
|
213
|
+
# This allows users to refer to the long or short switch and get
|
214
|
+
# the same value
|
215
|
+
hash.each{ |switch, val|
|
216
|
+
if syns.keys.include?(switch)
|
217
|
+
syns[switch].each{ |key|
|
218
|
+
hash[key] = val
|
219
|
+
}
|
220
|
+
end
|
221
|
+
}
|
222
|
+
|
223
|
+
# Get rid of leading "--" and "-" to make it easier to reference
|
224
|
+
hash.each{ |key, value|
|
225
|
+
if key[0,2] == '--'
|
226
|
+
nkey = key.sub('--', '')
|
227
|
+
else
|
228
|
+
nkey = key.sub('-', '')
|
229
|
+
end
|
230
|
+
hash.delete(key)
|
231
|
+
hash[nkey] = value
|
232
|
+
}
|
233
|
+
|
234
|
+
hash
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
end
|
data/lib/thor.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
2
|
+
require "getopt"
|
3
|
+
|
4
|
+
class Thor
|
5
|
+
def self.inherited(klass)
|
6
|
+
subclass_files[File.expand_path(caller[0].split(":")[0])] << klass
|
7
|
+
subclasses << klass unless subclasses.include?(klass)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.subclass_files
|
11
|
+
@subclass_files ||= Hash.new {|h,k| h[k] = []}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.subclasses
|
15
|
+
@subclasses ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.method_added(meth)
|
19
|
+
meth = meth.to_s
|
20
|
+
return if !public_instance_methods.include?(meth) || !@usage
|
21
|
+
@descriptions ||= []
|
22
|
+
@usages ||= []
|
23
|
+
@opts ||= []
|
24
|
+
|
25
|
+
@descriptions.delete(@descriptions.assoc(meth))
|
26
|
+
@descriptions << [meth, @desc]
|
27
|
+
|
28
|
+
@usages.delete(@usages.assoc(meth))
|
29
|
+
@usages << [meth, @usage]
|
30
|
+
|
31
|
+
@opts.delete(@opts.assoc(meth))
|
32
|
+
@opts << [meth, @method_options] if @method_options
|
33
|
+
|
34
|
+
@usage, @desc, @method_options = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.map(map)
|
38
|
+
@map ||= superclass.instance_variable_get("@map") || {}
|
39
|
+
@map.merge! map
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.desc(usage, description)
|
43
|
+
@usage, @desc = usage, description
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.method_options(opts)
|
47
|
+
@method_options = opts.inject({}) do |accum, (k,v)|
|
48
|
+
accum.merge("--" + k.to_s => v.to_s.upcase)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.help_list
|
53
|
+
return nil unless @usages
|
54
|
+
@help_list ||= begin
|
55
|
+
max_usage = @usages.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
|
56
|
+
max_opts = @opts.empty? ? 0 : format_opts(@opts.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last).size
|
57
|
+
max_desc = @descriptions.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
|
58
|
+
Struct.new(:klass, :usages, :opts, :descriptions, :max).new(
|
59
|
+
self, @usages, @opts, @descriptions, Struct.new(:usage, :opt, :desc).new(max_usage, max_opts, max_desc)
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.format_opts(opts)
|
65
|
+
return "" if !opts
|
66
|
+
opts.map do |opt, val|
|
67
|
+
if val == true || val == "BOOLEAN"
|
68
|
+
"[#{opt}]"
|
69
|
+
elsif val == "REQUIRED"
|
70
|
+
opt + "=" + opt.gsub(/\-/, "").upcase
|
71
|
+
elsif val == "OPTIONAL"
|
72
|
+
"[" + opt + "=" + opt.gsub(/\-/, "").upcase + "]"
|
73
|
+
end
|
74
|
+
end.join(" ")
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.start
|
78
|
+
meth = ARGV.shift
|
79
|
+
params = []
|
80
|
+
while !ARGV.empty?
|
81
|
+
break if ARGV.first =~ /^\-/
|
82
|
+
params << ARGV.shift
|
83
|
+
end
|
84
|
+
if defined?(@map) && @map[meth]
|
85
|
+
meth = @map[meth].to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
args = ARGV.dup
|
89
|
+
|
90
|
+
if @opts.assoc(meth)
|
91
|
+
opts = @opts.assoc(meth).last.map {|opt, val| [opt, val == true ? Getopt::BOOLEAN : Getopt.const_get(val)].flatten}
|
92
|
+
options = Getopt::Long.getopts(*opts)
|
93
|
+
params << options
|
94
|
+
end
|
95
|
+
|
96
|
+
ARGV.replace args
|
97
|
+
|
98
|
+
new(meth, params).instance_variable_get("@results")
|
99
|
+
end
|
100
|
+
|
101
|
+
def initialize(op, params)
|
102
|
+
begin
|
103
|
+
op ||= "help"
|
104
|
+
@results = send(op.to_sym, *params) if public_methods.include?(op) || !methods.include?(op)
|
105
|
+
rescue ArgumentError
|
106
|
+
puts "`#{op}' was called incorrectly. Call as `#{usage(op)}'"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
public :initialize
|
111
|
+
|
112
|
+
def usage(meth)
|
113
|
+
list = self.class.help_list
|
114
|
+
list.usages.assoc(meth)[1] + (list.opts.assoc(meth) ? " " + self.class.format_opts(list.opts.assoc(meth)[1]) : "")
|
115
|
+
end
|
116
|
+
|
117
|
+
map "--help" => :help
|
118
|
+
|
119
|
+
desc "help", "show this screen"
|
120
|
+
def help
|
121
|
+
list = self.class.help_list
|
122
|
+
puts "Options"
|
123
|
+
puts "-------"
|
124
|
+
list.usages.each do |meth, use|
|
125
|
+
format = "%-" + (list.max.usage + list.max.opt + 4).to_s + "s"
|
126
|
+
print format % ("#{usage(meth)}")
|
127
|
+
puts list.descriptions.assoc(meth)[1]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
data/lib/thor/tasks.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
class Thor
|
5
|
+
def self.package_task
|
6
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
7
|
+
desc "package", "package up the gem"
|
8
|
+
def package
|
9
|
+
FileUtils.mkdir_p(File.join(Dir.pwd, "pkg"))
|
10
|
+
Gem::Builder.new(SPEC).build
|
11
|
+
FileUtils.mv(SPEC.file_name, File.join(Dir.pwd, "pkg", SPEC.file_name))
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.install_task
|
17
|
+
package_task
|
18
|
+
|
19
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
20
|
+
desc "install", "install the gem"
|
21
|
+
def install
|
22
|
+
old_stderr, $stderr = $stderr.dup, File.open("/dev/null", "w")
|
23
|
+
package
|
24
|
+
$stderr = old_stderr
|
25
|
+
system %{sudo gem install pkg/#{GEM}-#{GEM_VERSION} --no-rdoc --no-ri --no-update-sources}
|
26
|
+
end
|
27
|
+
RUBY
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.spec_task(file_list, opts = {})
|
31
|
+
name = opts.delete(:name) || "spec"
|
32
|
+
rcov_dir = opts.delete(:rcov_dir) || "coverage"
|
33
|
+
file_list = file_list.map {|f| %["#{f}"]}.join(" ")
|
34
|
+
verbose = opts.delete(:verbose)
|
35
|
+
opts = {:format => "specdoc", :color => true}.merge(opts)
|
36
|
+
|
37
|
+
rcov_opts = convert_task_options(opts.delete(:rcov) || {})
|
38
|
+
rcov = !rcov_opts.empty?
|
39
|
+
options = convert_task_options(opts)
|
40
|
+
|
41
|
+
if rcov
|
42
|
+
FileUtils.rm_rf(File.join(Dir.pwd, rcov_dir))
|
43
|
+
end
|
44
|
+
|
45
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
46
|
+
desc("#{name}", "spec task")
|
47
|
+
def #{name}
|
48
|
+
cmd = "ruby "
|
49
|
+
if #{rcov.inspect}
|
50
|
+
cmd << "-S rcov -o #{rcov_dir} #{rcov_opts.inspect[1...-1]} "
|
51
|
+
end
|
52
|
+
cmd << `which spec`.chomp
|
53
|
+
cmd << " -- " if #{rcov.inspect}
|
54
|
+
cmd << " "
|
55
|
+
cmd << #{file_list.inspect}
|
56
|
+
cmd << " "
|
57
|
+
cmd << #{options.inspect}
|
58
|
+
puts cmd if #{verbose.inspect}
|
59
|
+
system(cmd)
|
60
|
+
end
|
61
|
+
RUBY
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def self.convert_task_options(opts)
|
66
|
+
opts.map do |key, value|
|
67
|
+
if value == true
|
68
|
+
"--#{key}"
|
69
|
+
elsif value.is_a?(Array)
|
70
|
+
value.map {|v| "--#{key} #{v.inspect}"}.join(" ")
|
71
|
+
else
|
72
|
+
"--#{key} #{value.inspect}"
|
73
|
+
end
|
74
|
+
end.join(" ")
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,1090 @@
|
|
1
|
+
require 'vendor/sexp_processor'
|
2
|
+
require 'vendor/unified_ruby'
|
3
|
+
|
4
|
+
class Ruby2Ruby < SexpProcessor
|
5
|
+
include UnifiedRuby
|
6
|
+
|
7
|
+
VERSION = '1.1.8'
|
8
|
+
LINE_LENGTH = 78
|
9
|
+
|
10
|
+
##
|
11
|
+
# Nodes that represent assignment and probably need () around them.
|
12
|
+
|
13
|
+
ASSIGN_NODES = [
|
14
|
+
:dasgn,
|
15
|
+
:flip2,
|
16
|
+
:flip3,
|
17
|
+
:lasgn,
|
18
|
+
:masgn,
|
19
|
+
:op_asgn1,
|
20
|
+
:op_asgn2,
|
21
|
+
:op_asgn_and,
|
22
|
+
:op_asgn_or,
|
23
|
+
:return,
|
24
|
+
]
|
25
|
+
|
26
|
+
def self.translate(klass_or_str, method = nil)
|
27
|
+
self.new.process(ParseTree.translate(klass_or_str, method))
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
super
|
32
|
+
@indent = " "
|
33
|
+
self.auto_shift_type = true
|
34
|
+
self.strict = true
|
35
|
+
self.expected = String
|
36
|
+
|
37
|
+
# self.debug[:defn] = /zsuper/
|
38
|
+
end
|
39
|
+
|
40
|
+
def process exp
|
41
|
+
exp = Sexp.from_array(exp) if Array === exp unless Sexp === exp
|
42
|
+
super exp
|
43
|
+
end
|
44
|
+
|
45
|
+
############################################################
|
46
|
+
# Processors
|
47
|
+
|
48
|
+
def process_alias(exp)
|
49
|
+
"alias_method #{process(exp.shift)}, #{process(exp.shift)}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_and(exp)
|
53
|
+
"(#{process exp.shift} and #{process exp.shift})"
|
54
|
+
end
|
55
|
+
|
56
|
+
def process_args(exp)
|
57
|
+
args = []
|
58
|
+
|
59
|
+
until exp.empty? do
|
60
|
+
arg = exp.shift
|
61
|
+
case arg
|
62
|
+
when Symbol then
|
63
|
+
args << arg
|
64
|
+
when Array then
|
65
|
+
case arg.first
|
66
|
+
when :block then
|
67
|
+
asgns = {}
|
68
|
+
arg[1..-1].each do |lasgn|
|
69
|
+
asgns[lasgn[1]] = process(lasgn)
|
70
|
+
end
|
71
|
+
|
72
|
+
args.each_with_index do |name, index|
|
73
|
+
args[index] = asgns[name] if asgns.has_key? name
|
74
|
+
end
|
75
|
+
when :block_arg then
|
76
|
+
args << "&#{arg.last}"
|
77
|
+
else
|
78
|
+
raise "unknown arg type #{arg.first.inspect}"
|
79
|
+
end
|
80
|
+
else
|
81
|
+
raise "unknown arg type #{arg.inspect}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
return "(#{args.join ', '})"
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_arglist(exp) # custom made node
|
89
|
+
code = []
|
90
|
+
until exp.empty? do
|
91
|
+
code << process(exp.shift)
|
92
|
+
end
|
93
|
+
code.join ', '
|
94
|
+
end
|
95
|
+
|
96
|
+
def process_argscat(exp)
|
97
|
+
args = []
|
98
|
+
|
99
|
+
ary = exp.shift
|
100
|
+
ary.shift # :array
|
101
|
+
until ary.empty? do
|
102
|
+
args << process(ary.shift)
|
103
|
+
end
|
104
|
+
|
105
|
+
args << "*#{process(exp.shift)}"
|
106
|
+
args << process(exp.shift) unless exp.empty? # optional block arg
|
107
|
+
|
108
|
+
args.join ', '
|
109
|
+
end
|
110
|
+
|
111
|
+
def process_argspush(exp)
|
112
|
+
process_arglist(exp)
|
113
|
+
end
|
114
|
+
|
115
|
+
def process_array(exp)
|
116
|
+
"[#{process_arglist(exp)}]"
|
117
|
+
end
|
118
|
+
|
119
|
+
def process_attrasgn(exp)
|
120
|
+
receiver = process exp.shift
|
121
|
+
name = exp.shift
|
122
|
+
args = exp.empty? ? nil : exp.shift
|
123
|
+
|
124
|
+
case name
|
125
|
+
when :[]= then
|
126
|
+
rhs = process args.pop
|
127
|
+
args[0] = :arglist if args[0] == :array
|
128
|
+
"#{receiver}[#{process(args)}] = #{rhs}"
|
129
|
+
else
|
130
|
+
if args then
|
131
|
+
"#{receiver}.#{name.to_s[0..-2]} = #{process(args)[1..-2]}"
|
132
|
+
else
|
133
|
+
"#{receiver}.#{name.to_s[0..-2]}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def process_back_ref(exp)
|
139
|
+
"$#{exp.shift}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def process_begin(exp)
|
143
|
+
is_rescue = exp.first.first == :rescue rescue false
|
144
|
+
code = []
|
145
|
+
code << "begin"
|
146
|
+
until exp.empty?
|
147
|
+
src = process(exp.shift)
|
148
|
+
src = indent(src) unless src =~ /(^|\n)rescue/ # ensures no level 0 rescues
|
149
|
+
code << src
|
150
|
+
end
|
151
|
+
code << "end" unless is_rescue
|
152
|
+
return code.join("\n")
|
153
|
+
end
|
154
|
+
|
155
|
+
def process_block(exp)
|
156
|
+
result = []
|
157
|
+
|
158
|
+
exp << nil if exp.empty?
|
159
|
+
until exp.empty? do
|
160
|
+
code = exp.shift
|
161
|
+
if code.nil? or code.first == :nil then
|
162
|
+
result << "# do nothing"
|
163
|
+
else
|
164
|
+
result << process(code)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
result = result.join "\n"
|
169
|
+
|
170
|
+
result = case self.context[1]
|
171
|
+
when nil, :scope, :if, :iter, :resbody, :when, :while then
|
172
|
+
result + "\n"
|
173
|
+
else
|
174
|
+
"(#{result})"
|
175
|
+
end
|
176
|
+
|
177
|
+
return result
|
178
|
+
end
|
179
|
+
|
180
|
+
def process_block_arg(exp)
|
181
|
+
"&#{exp.shift}"
|
182
|
+
end
|
183
|
+
|
184
|
+
def process_block_pass(exp)
|
185
|
+
bname = s(:block_arg, process(exp.shift)) # FIX
|
186
|
+
call = exp.shift
|
187
|
+
|
188
|
+
if Array === call.last then # HACK - I _really_ need rewrites to happen first
|
189
|
+
case call.last.first
|
190
|
+
when :splat then
|
191
|
+
call << [:array, call.pop]
|
192
|
+
when :array then
|
193
|
+
# do nothing
|
194
|
+
else
|
195
|
+
has_args = Array === call.last and call.last.first == :array
|
196
|
+
call << [:array] unless has_args
|
197
|
+
end
|
198
|
+
call.last << bname
|
199
|
+
else
|
200
|
+
call << [:array, bname]
|
201
|
+
end
|
202
|
+
|
203
|
+
process(call)
|
204
|
+
end
|
205
|
+
|
206
|
+
def process_break(exp)
|
207
|
+
val = exp.empty? ? nil : process(exp.shift)
|
208
|
+
# HACK "break" + (val ? " #{val}" : "")
|
209
|
+
if val then
|
210
|
+
"break #{val}"
|
211
|
+
else
|
212
|
+
"break"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def process_call(exp)
|
217
|
+
receiver_node_type = exp.first.nil? ? nil : exp.first.first
|
218
|
+
receiver = process exp.shift
|
219
|
+
|
220
|
+
receiver = "(#{receiver})" if
|
221
|
+
Ruby2Ruby::ASSIGN_NODES.include? receiver_node_type
|
222
|
+
|
223
|
+
name = exp.shift
|
224
|
+
args_exp = exp.shift rescue nil
|
225
|
+
if args_exp && args_exp.first == :array # FIX
|
226
|
+
args = "#{process(args_exp)[1..-2]}"
|
227
|
+
else
|
228
|
+
args = process args_exp
|
229
|
+
args = nil if args.empty?
|
230
|
+
end
|
231
|
+
|
232
|
+
case name
|
233
|
+
when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>>, :** then
|
234
|
+
"(#{receiver} #{name} #{args})"
|
235
|
+
when :[] then
|
236
|
+
"#{receiver}[#{args}]"
|
237
|
+
when :"-@" then
|
238
|
+
"-#{receiver}"
|
239
|
+
when :"+@" then
|
240
|
+
"+#{receiver}"
|
241
|
+
else
|
242
|
+
unless receiver.nil? then
|
243
|
+
"#{receiver}.#{name}#{args ? "(#{args})" : args}"
|
244
|
+
else
|
245
|
+
"#{name}#{args ? "(#{args})" : args}"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def process_case(exp)
|
251
|
+
result = []
|
252
|
+
expr = process exp.shift
|
253
|
+
if expr then
|
254
|
+
result << "case #{expr}"
|
255
|
+
else
|
256
|
+
result << "case"
|
257
|
+
end
|
258
|
+
until exp.empty?
|
259
|
+
pt = exp.shift
|
260
|
+
if pt and pt.first == :when
|
261
|
+
result << "#{process(pt)}"
|
262
|
+
else
|
263
|
+
code = indent(process(pt))
|
264
|
+
code = indent("# do nothing") if code =~ /^\s*$/
|
265
|
+
result << "else\n#{code}"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
result << "end"
|
269
|
+
result.join("\n")
|
270
|
+
end
|
271
|
+
|
272
|
+
def process_cdecl(exp)
|
273
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
274
|
+
end
|
275
|
+
|
276
|
+
def process_class(exp)
|
277
|
+
"class #{util_module_or_class(exp, true)}"
|
278
|
+
end
|
279
|
+
|
280
|
+
def process_colon2(exp)
|
281
|
+
"#{process(exp.shift)}::#{exp.shift}"
|
282
|
+
end
|
283
|
+
|
284
|
+
def process_colon3(exp)
|
285
|
+
"::#{exp.shift}"
|
286
|
+
end
|
287
|
+
|
288
|
+
def process_const(exp)
|
289
|
+
exp.shift.to_s
|
290
|
+
end
|
291
|
+
|
292
|
+
def process_cvar(exp)
|
293
|
+
"#{exp.shift}"
|
294
|
+
end
|
295
|
+
|
296
|
+
def process_cvasgn(exp)
|
297
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
298
|
+
end
|
299
|
+
|
300
|
+
def process_cvdecl(exp)
|
301
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
302
|
+
end
|
303
|
+
|
304
|
+
# (a, lit1) => "a = 1"
|
305
|
+
# (a, (b, lit2)) => "a = b = 2"
|
306
|
+
# (a, (b)) => ""
|
307
|
+
|
308
|
+
def process_dasgn_curr(exp)
|
309
|
+
lhs = exp.shift.to_s
|
310
|
+
rhs = (exp.empty? ? nil : exp.shift)
|
311
|
+
if rhs.nil? then
|
312
|
+
if self.context[1] == :block then
|
313
|
+
return ''
|
314
|
+
end
|
315
|
+
|
316
|
+
return lhs
|
317
|
+
end
|
318
|
+
return "#{lhs} = #{process rhs}" unless rhs.first == :dasgn_curr
|
319
|
+
|
320
|
+
# keep recursing. ensure that the leaf node assigns to _something_
|
321
|
+
"#{lhs} = #{process rhs}"
|
322
|
+
end
|
323
|
+
|
324
|
+
def process_dasgn(exp)
|
325
|
+
if exp.size == 1 then
|
326
|
+
exp.shift.to_s
|
327
|
+
else
|
328
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def process_defined(exp)
|
333
|
+
"defined? #{process(exp.shift)}"
|
334
|
+
end
|
335
|
+
|
336
|
+
def process_defn(exp)
|
337
|
+
type1 = exp[1].first
|
338
|
+
type2 = exp[2].first rescue nil
|
339
|
+
|
340
|
+
if type1 == :args and [:ivar, :attrset].include? type2 then
|
341
|
+
name = exp.shift
|
342
|
+
case type2
|
343
|
+
when :ivar then
|
344
|
+
exp.clear
|
345
|
+
return "attr_reader #{name.inspect}"
|
346
|
+
when :attrset then
|
347
|
+
exp.clear
|
348
|
+
return "attr_writer :#{name.to_s[0..-2]}"
|
349
|
+
else
|
350
|
+
raise "Unknown defn type: #{exp.inspect}"
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
case type1
|
355
|
+
when :scope, :args then
|
356
|
+
name = exp.shift
|
357
|
+
args = process(exp.shift)
|
358
|
+
args = "" if args == "()"
|
359
|
+
body = indent(process(exp.shift))
|
360
|
+
return "def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n")
|
361
|
+
else
|
362
|
+
raise "Unknown defn type: #{type1} for #{exp.inspect}"
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def process_defs(exp)
|
367
|
+
exp.unshift "#{process(exp.shift)}.#{exp.shift}"
|
368
|
+
process_defn(exp)
|
369
|
+
end
|
370
|
+
|
371
|
+
def process_dot2(exp)
|
372
|
+
"(#{process exp.shift}..#{process exp.shift})"
|
373
|
+
end
|
374
|
+
|
375
|
+
def process_dot3(exp)
|
376
|
+
"(#{process exp.shift}...#{process exp.shift})"
|
377
|
+
end
|
378
|
+
|
379
|
+
def process_dregx(exp)
|
380
|
+
"/" << util_dthing(exp, true) << "/"
|
381
|
+
end
|
382
|
+
|
383
|
+
def process_dregx_once(exp)
|
384
|
+
process_dregx(exp) + "o"
|
385
|
+
end
|
386
|
+
|
387
|
+
def process_dstr(exp)
|
388
|
+
"\"#{util_dthing(exp)}\""
|
389
|
+
end
|
390
|
+
|
391
|
+
def process_dsym(exp)
|
392
|
+
":#{process_dstr(exp)}"
|
393
|
+
end
|
394
|
+
|
395
|
+
def process_dvar(exp)
|
396
|
+
exp.shift.to_s
|
397
|
+
end
|
398
|
+
|
399
|
+
def process_dxstr(exp)
|
400
|
+
"`#{process_dstr(exp)[1..-2]}`"
|
401
|
+
end
|
402
|
+
|
403
|
+
def process_ensure(exp)
|
404
|
+
body = process exp.shift
|
405
|
+
ens = process exp.shift
|
406
|
+
return "#{body}\nensure\n#{indent ens}"
|
407
|
+
end
|
408
|
+
|
409
|
+
def process_evstr(exp)
|
410
|
+
process exp.shift
|
411
|
+
end
|
412
|
+
|
413
|
+
def process_false(exp)
|
414
|
+
"false"
|
415
|
+
end
|
416
|
+
|
417
|
+
# TODO: remove for unified
|
418
|
+
def process_fcall(exp)
|
419
|
+
recv = exp.shift unless Symbol === exp.first # HACK conditional - some not getting rewritten?
|
420
|
+
name = exp.shift.to_s
|
421
|
+
args = exp.shift
|
422
|
+
code = []
|
423
|
+
unless args.nil? then
|
424
|
+
args[0] = :arglist if args.first == :array
|
425
|
+
code << process(args)
|
426
|
+
end
|
427
|
+
return code.empty? ? name : "#{name}(#{code.join(', ')})"
|
428
|
+
end
|
429
|
+
|
430
|
+
def process_flip2(exp)
|
431
|
+
"#{process(exp.shift)}..#{process(exp.shift)}"
|
432
|
+
end
|
433
|
+
|
434
|
+
def process_flip3(exp)
|
435
|
+
"#{process(exp.shift)}...#{process(exp.shift)}"
|
436
|
+
end
|
437
|
+
|
438
|
+
def process_for(exp)
|
439
|
+
recv = process exp.shift
|
440
|
+
iter = process exp.shift
|
441
|
+
body = exp.empty? ? nil : process(exp.shift)
|
442
|
+
|
443
|
+
result = ["for #{iter} in #{recv} do"]
|
444
|
+
result << indent(body ? body : "# do nothing")
|
445
|
+
result << "end"
|
446
|
+
|
447
|
+
result.join("\n")
|
448
|
+
end
|
449
|
+
|
450
|
+
def process_gasgn(exp)
|
451
|
+
process_iasgn(exp)
|
452
|
+
end
|
453
|
+
|
454
|
+
def process_gvar(exp)
|
455
|
+
return exp.shift.to_s
|
456
|
+
end
|
457
|
+
|
458
|
+
def process_hash(exp)
|
459
|
+
result = []
|
460
|
+
until exp.empty?
|
461
|
+
result << "#{process(exp.shift)} => #{process(exp.shift)}"
|
462
|
+
end
|
463
|
+
|
464
|
+
case self.context[1]
|
465
|
+
when :arglist, :argscat then
|
466
|
+
return "#{result.join(', ')}" # HACK - this will break w/ 2 hashes as args
|
467
|
+
else
|
468
|
+
return "{ #{result.join(', ')} }"
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def process_iasgn(exp)
|
473
|
+
lhs = exp.shift
|
474
|
+
if exp.empty? then # part of an masgn
|
475
|
+
lhs.to_s
|
476
|
+
else
|
477
|
+
"#{lhs} = #{process exp.shift}"
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def process_if(exp)
|
482
|
+
expand = Ruby2Ruby::ASSIGN_NODES.include? exp.first.first
|
483
|
+
c = process exp.shift
|
484
|
+
t = process exp.shift
|
485
|
+
f = process exp.shift
|
486
|
+
|
487
|
+
c = "(#{c.chomp})" if c =~ /\n/
|
488
|
+
|
489
|
+
if t then
|
490
|
+
unless expand then
|
491
|
+
if f then
|
492
|
+
r = "#{c} ? (#{t}) : (#{f})"
|
493
|
+
r = nil if r =~ /return/ # HACK - need contextual awareness or something
|
494
|
+
else
|
495
|
+
r = "#{t} if #{c}"
|
496
|
+
end
|
497
|
+
return r if r and (@indent+r).size < LINE_LENGTH and r !~ /\n/
|
498
|
+
end
|
499
|
+
|
500
|
+
r = "if #{c} then\n#{indent(t)}\n"
|
501
|
+
r << "else\n#{indent(f)}\n" if f
|
502
|
+
r << "end"
|
503
|
+
|
504
|
+
r
|
505
|
+
else
|
506
|
+
unless expand then
|
507
|
+
r = "#{f} unless #{c}"
|
508
|
+
return r if (@indent+r).size < LINE_LENGTH and r !~ /\n/
|
509
|
+
end
|
510
|
+
"unless #{c} then\n#{indent(f)}\nend"
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
def process_iter(exp)
|
515
|
+
iter = process exp.shift
|
516
|
+
args = exp.shift
|
517
|
+
args = (args == 0) ? '' : process(args)
|
518
|
+
body = exp.empty? ? nil : process(exp.shift)
|
519
|
+
|
520
|
+
b, e = if iter == "END" then
|
521
|
+
[ "{", "}" ]
|
522
|
+
else
|
523
|
+
[ "do", "end" ]
|
524
|
+
end
|
525
|
+
|
526
|
+
iter.sub!(/\(\)$/, '')
|
527
|
+
|
528
|
+
# REFACTOR: ugh
|
529
|
+
result = []
|
530
|
+
result << "#{iter} {"
|
531
|
+
result << " |#{args}|" if args
|
532
|
+
if body then
|
533
|
+
result << " #{body.strip} "
|
534
|
+
else
|
535
|
+
result << ' '
|
536
|
+
end
|
537
|
+
result << "}"
|
538
|
+
result = result.join
|
539
|
+
return result if result !~ /\n/ and result.size < LINE_LENGTH
|
540
|
+
|
541
|
+
result = []
|
542
|
+
result << "#{iter} #{b}"
|
543
|
+
result << " |#{args}|" if args
|
544
|
+
result << "\n"
|
545
|
+
result << indent(body.strip)
|
546
|
+
result << "\n"
|
547
|
+
result << e
|
548
|
+
result.join
|
549
|
+
end
|
550
|
+
|
551
|
+
def process_ivar(exp)
|
552
|
+
exp.shift.to_s
|
553
|
+
end
|
554
|
+
|
555
|
+
def process_lasgn(exp)
|
556
|
+
s = "#{exp.shift}"
|
557
|
+
s += " = #{process exp.shift}" unless exp.empty?
|
558
|
+
s
|
559
|
+
end
|
560
|
+
|
561
|
+
def process_lit(exp)
|
562
|
+
obj = exp.shift
|
563
|
+
case obj
|
564
|
+
when Range then
|
565
|
+
"(#{obj.inspect})"
|
566
|
+
else
|
567
|
+
obj.inspect
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def process_lvar(exp)
|
572
|
+
exp.shift.to_s
|
573
|
+
end
|
574
|
+
|
575
|
+
def splat(sym)
|
576
|
+
:"*#{sym}"
|
577
|
+
end
|
578
|
+
|
579
|
+
def process_masgn(exp)
|
580
|
+
lhs = exp.shift
|
581
|
+
rhs = exp.empty? ? nil : exp.shift
|
582
|
+
|
583
|
+
unless exp.empty? then
|
584
|
+
rhs[-1] = splat(rhs[-1]) unless rhs == s(:splat)
|
585
|
+
lhs << rhs
|
586
|
+
rhs = exp.shift
|
587
|
+
end
|
588
|
+
|
589
|
+
case lhs.first
|
590
|
+
when :array then
|
591
|
+
lhs.shift
|
592
|
+
lhs = lhs.map do |l|
|
593
|
+
case l.first
|
594
|
+
when :masgn then
|
595
|
+
"(#{process(l)})"
|
596
|
+
else
|
597
|
+
process(l)
|
598
|
+
end
|
599
|
+
end
|
600
|
+
when :dasgn_curr then
|
601
|
+
lhs = [ splat(lhs.last) ]
|
602
|
+
when :splat then
|
603
|
+
lhs = [ :"*" ]
|
604
|
+
else
|
605
|
+
raise "no clue: #{lhs.inspect}"
|
606
|
+
end
|
607
|
+
|
608
|
+
if context[1] == :iter and rhs then
|
609
|
+
lhs << splat(rhs.last)
|
610
|
+
rhs = nil
|
611
|
+
end
|
612
|
+
|
613
|
+
unless rhs.nil? then
|
614
|
+
t = rhs.first
|
615
|
+
rhs = if t == :argscat then
|
616
|
+
rhs.shift
|
617
|
+
process_argscat(rhs)
|
618
|
+
else
|
619
|
+
r = process(rhs)
|
620
|
+
r = r[1..-2] if t != :to_ary
|
621
|
+
r
|
622
|
+
end
|
623
|
+
return "#{lhs.join(", ")} = #{rhs}"
|
624
|
+
else
|
625
|
+
return lhs.join(", ")
|
626
|
+
end
|
627
|
+
|
628
|
+
end
|
629
|
+
|
630
|
+
def process_match(exp)
|
631
|
+
"#{process(exp.shift)}"
|
632
|
+
end
|
633
|
+
|
634
|
+
def process_match2(exp)
|
635
|
+
lhs = process(exp.shift)
|
636
|
+
rhs = process(exp.shift)
|
637
|
+
"#{lhs} =~ #{rhs}"
|
638
|
+
end
|
639
|
+
|
640
|
+
def process_match3(exp)
|
641
|
+
rhs = process(exp.shift)
|
642
|
+
lhs = process(exp.shift)
|
643
|
+
"#{lhs} =~ #{rhs}"
|
644
|
+
end
|
645
|
+
|
646
|
+
def process_module(exp)
|
647
|
+
"module #{util_module_or_class(exp)}"
|
648
|
+
end
|
649
|
+
|
650
|
+
def process_next(exp)
|
651
|
+
val = exp.empty? ? nil : process(exp.shift)
|
652
|
+
if val then
|
653
|
+
"next #{val}"
|
654
|
+
else
|
655
|
+
"next"
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
def process_nil(exp)
|
660
|
+
"nil"
|
661
|
+
end
|
662
|
+
|
663
|
+
def process_not(exp)
|
664
|
+
"(not #{process exp.shift})"
|
665
|
+
end
|
666
|
+
|
667
|
+
def process_nth_ref(exp)
|
668
|
+
"$#{exp.shift}"
|
669
|
+
end
|
670
|
+
|
671
|
+
def process_op_asgn1(exp)
|
672
|
+
# [[:lvar, :b], [:array, [:lit, 1]], :"||", [:lit, 10]]
|
673
|
+
lhs = process(exp.shift)
|
674
|
+
index = process(exp.shift)
|
675
|
+
msg = exp.shift
|
676
|
+
rhs = process(exp.shift)
|
677
|
+
|
678
|
+
"#{lhs}#{index} #{msg}= #{rhs}"
|
679
|
+
end
|
680
|
+
|
681
|
+
def process_op_asgn2(exp)
|
682
|
+
# [[:lvar, :c], :var=, :"||", [:lit, 20]]
|
683
|
+
lhs = process(exp.shift)
|
684
|
+
index = exp.shift.to_s[0..-2]
|
685
|
+
msg = exp.shift
|
686
|
+
|
687
|
+
rhs = process(exp.shift)
|
688
|
+
|
689
|
+
"#{lhs}.#{index} #{msg}= #{rhs}"
|
690
|
+
end
|
691
|
+
|
692
|
+
def process_op_asgn_or(exp)
|
693
|
+
# a ||= 1
|
694
|
+
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
|
695
|
+
exp.shift
|
696
|
+
process(exp.shift).sub(/=/, '||=')
|
697
|
+
end
|
698
|
+
|
699
|
+
def process_op_asgn_and(exp)
|
700
|
+
# a &&= 1
|
701
|
+
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
|
702
|
+
exp.shift
|
703
|
+
process(exp.shift).sub(/=/, '&&=')
|
704
|
+
end
|
705
|
+
|
706
|
+
def process_or(exp)
|
707
|
+
"(#{process exp.shift} or #{process exp.shift})"
|
708
|
+
end
|
709
|
+
|
710
|
+
def process_postexe(exp)
|
711
|
+
"END"
|
712
|
+
end
|
713
|
+
|
714
|
+
def process_redo(exp)
|
715
|
+
"redo"
|
716
|
+
end
|
717
|
+
|
718
|
+
def process_resbody(exp) # TODO: rewrite this fucker
|
719
|
+
code = []
|
720
|
+
|
721
|
+
sexp = exp
|
722
|
+
until exp.empty? and (sexp.nil? or sexp.empty?)
|
723
|
+
list = sexp.shift
|
724
|
+
body = sexp.shift
|
725
|
+
|
726
|
+
var = if list and
|
727
|
+
list.size > 1 and
|
728
|
+
[:lasgn, :dasgn, :dasgn_curr].include? list.last.first then
|
729
|
+
list.pop[1]
|
730
|
+
else
|
731
|
+
nil
|
732
|
+
end
|
733
|
+
|
734
|
+
# FIX: omg this is horrid. I should be punished
|
735
|
+
var = body.delete_at(1)[1] if
|
736
|
+
[:dasgn_curr, :dasgn].include? body[1][0] unless
|
737
|
+
var or body.nil? rescue nil
|
738
|
+
|
739
|
+
if list and list.size > 1 then
|
740
|
+
list[0] = :arglist
|
741
|
+
code << "rescue #{process(list)}"
|
742
|
+
else
|
743
|
+
code << "rescue"
|
744
|
+
end
|
745
|
+
|
746
|
+
code.last << " => #{var}" if var
|
747
|
+
|
748
|
+
if body then
|
749
|
+
code << indent(process(body)).chomp
|
750
|
+
else
|
751
|
+
code << indent("# do nothing")
|
752
|
+
end
|
753
|
+
|
754
|
+
unless exp.empty? then
|
755
|
+
sexp = exp.shift
|
756
|
+
assert_type sexp, :resbody
|
757
|
+
sexp.shift
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
code.join("\n")
|
762
|
+
end
|
763
|
+
|
764
|
+
def process_rescue(exp)
|
765
|
+
# TODO: rewrite this
|
766
|
+
#
|
767
|
+
# a = b rescue c => [lasgn a [rescue b c]]
|
768
|
+
# begin; a = b; rescue c => [begin [rescue [lasgn a b] c]]
|
769
|
+
|
770
|
+
current = self.context[1]
|
771
|
+
case current
|
772
|
+
when :begin, :ensure, :block then
|
773
|
+
body = (exp.first.first == :resbody) ? nil : process(exp.shift)
|
774
|
+
resbody = exp.empty? ? '' : process(exp.shift)
|
775
|
+
els = exp.empty? ? nil : process(exp.shift)
|
776
|
+
|
777
|
+
code = []
|
778
|
+
code << indent(body) if body
|
779
|
+
code << resbody
|
780
|
+
if els then
|
781
|
+
code << "else"
|
782
|
+
code << indent(els)
|
783
|
+
else
|
784
|
+
unless [:block].include? current then
|
785
|
+
code << "end\n" unless current == :ensure
|
786
|
+
else
|
787
|
+
r = [body, resbody.gsub(/rescue\n\s+/, 'rescue ')].compact.join(' ')
|
788
|
+
code = [r] if (@indent+r).size < LINE_LENGTH and r !~ /\n/
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
code.join("\n").chomp
|
793
|
+
else # a rescue b and others
|
794
|
+
body = process exp.shift
|
795
|
+
assert_type exp.first, :resbody
|
796
|
+
resbody = exp.shift
|
797
|
+
resbody.shift # resbody
|
798
|
+
resbody.shift # nil (no types for expression form)
|
799
|
+
resbody = resbody.shift # actual code
|
800
|
+
|
801
|
+
resbody = process resbody
|
802
|
+
code = "#{body} rescue #{resbody}"
|
803
|
+
case current
|
804
|
+
when :hash then # HACK move to process_hash
|
805
|
+
"(#{code})"
|
806
|
+
else
|
807
|
+
code
|
808
|
+
end
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
def process_retry(exp)
|
813
|
+
"retry"
|
814
|
+
end
|
815
|
+
|
816
|
+
def process_return(exp)
|
817
|
+
# HACK return "return" + (exp.empty? ? "" : " #{process exp.shift}")
|
818
|
+
|
819
|
+
if exp.empty? then
|
820
|
+
return "return"
|
821
|
+
else
|
822
|
+
return "return #{process exp.shift}"
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
def process_sclass(exp)
|
827
|
+
"class << #{process(exp.shift)}\n#{indent(process(exp.shift))}\nend"
|
828
|
+
end
|
829
|
+
|
830
|
+
def process_scope(exp)
|
831
|
+
exp.empty? ? "" : process(exp.shift)
|
832
|
+
end
|
833
|
+
|
834
|
+
def process_self(exp)
|
835
|
+
"self"
|
836
|
+
end
|
837
|
+
|
838
|
+
def process_splat(exp)
|
839
|
+
if exp.empty? then
|
840
|
+
"*"
|
841
|
+
else
|
842
|
+
"*#{process(exp.shift)}"
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
def process_str(exp)
|
847
|
+
return exp.shift.dump
|
848
|
+
end
|
849
|
+
|
850
|
+
def process_super(exp)
|
851
|
+
args = exp.shift
|
852
|
+
args[0] = :arglist if args[0] == :array
|
853
|
+
"super(#{process(args)})"
|
854
|
+
end
|
855
|
+
|
856
|
+
def process_svalue(exp)
|
857
|
+
process(exp.shift)
|
858
|
+
end
|
859
|
+
|
860
|
+
def process_to_ary(exp)
|
861
|
+
process(exp.shift)
|
862
|
+
end
|
863
|
+
|
864
|
+
def process_true(exp)
|
865
|
+
"true"
|
866
|
+
end
|
867
|
+
|
868
|
+
def process_undef(exp)
|
869
|
+
"undef #{process(exp.shift)}"
|
870
|
+
end
|
871
|
+
|
872
|
+
def process_until(exp)
|
873
|
+
cond_loop(exp, 'until')
|
874
|
+
end
|
875
|
+
|
876
|
+
def process_valias(exp)
|
877
|
+
"alias #{exp.shift} #{exp.shift}"
|
878
|
+
end
|
879
|
+
|
880
|
+
def process_when(exp)
|
881
|
+
src = []
|
882
|
+
|
883
|
+
if self.context[1] == :array then # ugh. matz! why not an argscat?!?
|
884
|
+
val = process(exp.shift)
|
885
|
+
exp.shift # empty body
|
886
|
+
return "*#{val}"
|
887
|
+
end
|
888
|
+
|
889
|
+
until exp.empty?
|
890
|
+
cond = process(exp.shift).to_s[1..-2]
|
891
|
+
code = indent(process(exp.shift))
|
892
|
+
code = indent "# do nothing" if code =~ /\A\s*\Z/
|
893
|
+
src << "when #{cond} then\n#{code.chomp}"
|
894
|
+
end
|
895
|
+
|
896
|
+
src.join("\n")
|
897
|
+
end
|
898
|
+
|
899
|
+
def process_while(exp)
|
900
|
+
cond_loop(exp, 'while')
|
901
|
+
end
|
902
|
+
|
903
|
+
def process_xstr(exp)
|
904
|
+
"`#{process_str(exp)[1..-2]}`"
|
905
|
+
end
|
906
|
+
|
907
|
+
def process_yield(exp)
|
908
|
+
args = exp.empty? ? nil : exp.shift
|
909
|
+
if args then
|
910
|
+
args[0] = :arglist if args.first == :array
|
911
|
+
args = process(args)
|
912
|
+
end
|
913
|
+
|
914
|
+
# "yield" + (args ? "(#{args})" : "")
|
915
|
+
if args then
|
916
|
+
"yield(#{args})"
|
917
|
+
else
|
918
|
+
"yield"
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
922
|
+
def process_zarray(exp)
|
923
|
+
"[]"
|
924
|
+
end
|
925
|
+
|
926
|
+
def process_zsuper(exp)
|
927
|
+
"super"
|
928
|
+
end
|
929
|
+
|
930
|
+
def cond_loop(exp, name)
|
931
|
+
cond = process(exp.shift)
|
932
|
+
body = process(exp.shift)
|
933
|
+
head_controlled = exp.shift
|
934
|
+
|
935
|
+
body = indent(body).chomp if body
|
936
|
+
|
937
|
+
code = []
|
938
|
+
if head_controlled then
|
939
|
+
code << "#{name} #{cond} do"
|
940
|
+
code << body if body
|
941
|
+
code << "end"
|
942
|
+
else
|
943
|
+
code << "begin"
|
944
|
+
code << body if body
|
945
|
+
code << "end #{name} #{cond}"
|
946
|
+
end
|
947
|
+
code.join("\n")
|
948
|
+
end
|
949
|
+
|
950
|
+
############################################################
|
951
|
+
# Rewriters:
|
952
|
+
|
953
|
+
def rewrite_rescue exp
|
954
|
+
exp = s(:begin, exp) if
|
955
|
+
context[1] == :block unless
|
956
|
+
context[2] == :scope and [:defn, :defs].include? context[3]
|
957
|
+
exp
|
958
|
+
end
|
959
|
+
|
960
|
+
############################################################
|
961
|
+
# Utility Methods:
|
962
|
+
|
963
|
+
def util_dthing(exp, regx = false)
|
964
|
+
s = []
|
965
|
+
suck = true
|
966
|
+
if suck then
|
967
|
+
x = exp.shift.gsub(/"/, '\"').gsub(/\n/, '\n')
|
968
|
+
else
|
969
|
+
x = exp.shift.dump[1..-2]
|
970
|
+
end
|
971
|
+
x.gsub!(/\//, '\/') if regx
|
972
|
+
|
973
|
+
s << x
|
974
|
+
until exp.empty?
|
975
|
+
pt = exp.shift
|
976
|
+
case pt
|
977
|
+
when Sexp then
|
978
|
+
case pt.first
|
979
|
+
when :str then
|
980
|
+
if suck then
|
981
|
+
x = pt.last.gsub(/"/, '\"').gsub(/\n/, '\n')
|
982
|
+
else
|
983
|
+
x = pt.last.dump[1..-2]
|
984
|
+
end
|
985
|
+
x.gsub!(/\//, '\/') if regx
|
986
|
+
s << x
|
987
|
+
else
|
988
|
+
s << '#{' << process(pt) << '}' # do not use interpolation here
|
989
|
+
end
|
990
|
+
else
|
991
|
+
# do nothing - yet
|
992
|
+
end
|
993
|
+
end
|
994
|
+
|
995
|
+
s.join
|
996
|
+
end
|
997
|
+
|
998
|
+
def util_module_or_class(exp, is_class=false)
|
999
|
+
s = "#{exp.shift}"
|
1000
|
+
|
1001
|
+
if is_class then
|
1002
|
+
superk = process(exp.shift)
|
1003
|
+
s << " < #{superk}" if superk
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
s << "\n"
|
1007
|
+
|
1008
|
+
body = []
|
1009
|
+
begin
|
1010
|
+
code = process(exp.shift).chomp
|
1011
|
+
body << code unless code.nil? or code.empty?
|
1012
|
+
end until exp.empty?
|
1013
|
+
unless body.empty? then
|
1014
|
+
body = indent(body.join("\n\n")) + "\n"
|
1015
|
+
else
|
1016
|
+
body = ""
|
1017
|
+
end
|
1018
|
+
s + body + "end"
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def indent(s)
|
1022
|
+
s.to_s.map{|line| @indent + line}.join
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
RubyToRuby = Ruby2Ruby # For backwards compatibilty... TODO: remove 2008-03-28
|
1027
|
+
|
1028
|
+
class Method
|
1029
|
+
def with_class_and_method_name
|
1030
|
+
if self.inspect =~ /<Method: (.*)\#(.*)>/ then
|
1031
|
+
klass = eval $1
|
1032
|
+
method = $2.intern
|
1033
|
+
raise "Couldn't determine class from #{self.inspect}" if klass.nil?
|
1034
|
+
return yield(klass, method)
|
1035
|
+
else
|
1036
|
+
raise "Can't parse signature: #{self.inspect}"
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
def to_sexp
|
1041
|
+
with_class_and_method_name do |klass, method|
|
1042
|
+
ParseTree.new(false).parse_tree_for_method(klass, method)
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
def to_ruby
|
1047
|
+
Ruby2Ruby.new.process(self.to_sexp)
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
class ProcStoreTmp
|
1052
|
+
@@n = 0
|
1053
|
+
def self.name
|
1054
|
+
@@n += 1
|
1055
|
+
return :"myproc#{@@n}"
|
1056
|
+
end
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
class UnboundMethod
|
1060
|
+
def to_ruby
|
1061
|
+
name = ProcStoreTmp.name
|
1062
|
+
ProcStoreTmp.send(:define_method, name, self)
|
1063
|
+
m = ProcStoreTmp.new.method(name)
|
1064
|
+
result = m.to_ruby.sub(/def #{name}(?:\(([^\)]*)\))?/,
|
1065
|
+
'proc { |\1|').sub(/end\Z/, '}')
|
1066
|
+
return result
|
1067
|
+
end
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
class Proc
|
1071
|
+
def to_method
|
1072
|
+
name = ProcStoreTmp.name
|
1073
|
+
ProcStoreTmp.send(:define_method, name, self)
|
1074
|
+
ProcStoreTmp.new.method(name)
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
def to_sexp
|
1078
|
+
body = self.to_method.to_sexp[2][1..-1]
|
1079
|
+
[:proc, *body]
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
def to_ruby
|
1083
|
+
ruby = self.to_method.to_ruby
|
1084
|
+
ruby.sub!(/\A(def \S+)\(([^\)]*)\)/, '\1 |\2|') # move args
|
1085
|
+
ruby.sub!(/\Adef[^\n\|]+/, 'proc { ') # strip def name
|
1086
|
+
ruby.sub!(/end\Z/, '}') # strip end
|
1087
|
+
ruby.gsub!(/\s+$/, '') # trailing WS bugs me
|
1088
|
+
ruby
|
1089
|
+
end
|
1090
|
+
end
|