partialruby 0.1.0
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/AUTHORS +1 -0
- data/CHANGELOG +3 -0
- data/LICENSE +674 -0
- data/README +89 -0
- data/Rakefile +47 -0
- data/TODO +3 -0
- data/lib/partialruby.rb +468 -0
- data/spec/block_spec.rb +83 -0
- data/spec/call_spec.rb +26 -0
- data/spec/class_spec.rb +34 -0
- data/spec/const_spec.rb +33 -0
- data/spec/def_spec.rb +35 -0
- data/spec/eval_spec.rb +85 -0
- data/spec/exception_spec.rb +53 -0
- data/spec/flow_control_spec.rb +38 -0
- data/spec/gvar_spec.rb +18 -0
- data/spec/ivar_spec.rb +18 -0
- data/spec/literal_spec.rb +24 -0
- data/spec/operator_spec.rb +39 -0
- data/spec/xstr_spec.rb +14 -0
- metadata +102 -0
data/README
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
= partialruby - Ruby partial interpreter written in pure ruby
|
2
|
+
|
3
|
+
What I trying to say with "partial" ? Well, the ruby interpreter is composed by a few main conceptual "components": parser, api, VM and execution environment. A partial interpreter will be a library implementing only one or even only part of one of these basic components.
|
4
|
+
In this case, partialruby only implements part of the VM (e.g. partialruby DOESN'T implement a GC), use the excenllent ruby_parser gem (https://github.com/seattlerb/ruby_parser) to parse ruby code and use the real interpreter to the rest (api, environment, etc...).
|
5
|
+
|
6
|
+
== Goals:
|
7
|
+
|
8
|
+
=== Implement a alternative VM which export services that is not exported by the original VM without implementing a entire ruby interpreter or fork an existing ruby interpreter
|
9
|
+
- Control of execution flow via hooking for sandboxing (see evalhook and shikashi projects)
|
10
|
+
- Fast DSL (over ruby, and faster than ruby itself!)
|
11
|
+
|
12
|
+
=== Proof of Concept of interpreter and partial interpreter development
|
13
|
+
|
14
|
+
- Hyper-portability: microruby
|
15
|
+
- Search for a faster ruby
|
16
|
+
|
17
|
+
== Installation
|
18
|
+
|
19
|
+
=== Gem Installation (pending)
|
20
|
+
|
21
|
+
sudo gem install partialruby
|
22
|
+
|
23
|
+
OR
|
24
|
+
|
25
|
+
* Download the last version of the gem from http://github.com/tario/partialruby/downloads
|
26
|
+
* Install the gem with the following;
|
27
|
+
|
28
|
+
sudo gem install partialruby-X.X.X.gem.
|
29
|
+
|
30
|
+
== Documentation (pending)
|
31
|
+
|
32
|
+
Full API documentation can be found on:
|
33
|
+
http://tario.github.com/partialruby/doc/
|
34
|
+
|
35
|
+
== Usage (pending)
|
36
|
+
|
37
|
+
Basically, partialruby export two APIs:
|
38
|
+
|
39
|
+
* A alernative eval function with context. Example:
|
40
|
+
|
41
|
+
require "partialruby"
|
42
|
+
|
43
|
+
context = PartialRuby::Context.new
|
44
|
+
context.eval('print "hello world\n"')
|
45
|
+
|
46
|
+
Or
|
47
|
+
|
48
|
+
require "partialruby"
|
49
|
+
|
50
|
+
PartialRuby.eval('print "hello world\n"')
|
51
|
+
|
52
|
+
* A flexible node handling. Example
|
53
|
+
|
54
|
+
require "partialruby"
|
55
|
+
|
56
|
+
class MyPartialRubyContext < PartialRuby::Context
|
57
|
+
|
58
|
+
def ruby_emul_call(tree)
|
59
|
+
object_tree = tree[1]
|
60
|
+
method_name = tree[2]
|
61
|
+
|
62
|
+
arglist = tree[3]
|
63
|
+
|
64
|
+
argsstr = arglist[1..-1].
|
65
|
+
map{|subtree| "(" + emul(subtree, frame) + ")" }.
|
66
|
+
join(",")
|
67
|
+
|
68
|
+
|
69
|
+
if (object_tree)
|
70
|
+
"((#{emul(object_tree)}).#{method_name}(#{argsstr})"
|
71
|
+
else
|
72
|
+
if arglist.count == 0
|
73
|
+
"#{method_name}(#{argsstr})"
|
74
|
+
else
|
75
|
+
"#{method_name}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
context = MyPartialRubyContext.new
|
84
|
+
context.eval('print "hello world\n"')
|
85
|
+
|
86
|
+
== Copying
|
87
|
+
|
88
|
+
Copyright (c) 2010-2011 Dario Seminara, released under the GPL License (see LICENSE)
|
89
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = 'partialruby'
|
9
|
+
s.version = '0.1.0'
|
10
|
+
s.author = 'Dario Seminara'
|
11
|
+
s.email = 'robertodarioseminara@gmail.com'
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.summary = 'Ruby partial interpreter written in pure-ruby '
|
14
|
+
s.homepage = "http://github.com/tario/partialruby"
|
15
|
+
s.add_dependency "ruby_parser", ">= 2.0.6"
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = [ 'README' ]
|
18
|
+
s.rdoc_options << '--main' << 'README'
|
19
|
+
s.files = Dir.glob("{examples,lib,spec}/**/*.rb") + [ 'LICENSE', 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Run tests'
|
23
|
+
task :default => [ :test ]
|
24
|
+
|
25
|
+
Rake::TestTask.new('test') do |t|
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = '{test}/**/test_*.rb'
|
28
|
+
t.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Generate RDoc'
|
32
|
+
Rake::RDocTask.new :rdoc do |rd|
|
33
|
+
rd.rdoc_dir = 'doc'
|
34
|
+
rd.rdoc_files.add 'lib', 'ext', 'README'
|
35
|
+
rd.main = 'README'
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'Build Gem'
|
39
|
+
Rake::GemPackageTask.new spec do |pkg|
|
40
|
+
pkg.need_tar = true
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Clean up'
|
44
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
45
|
+
|
46
|
+
desc 'Clean up'
|
47
|
+
task :clobber => [ :clean ]
|
data/TODO
ADDED
data/lib/partialruby.rb
ADDED
@@ -0,0 +1,468 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the partialruby project, http://github.com/tario/partialruby
|
4
|
+
|
5
|
+
Copyright (c) 2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
partialruby is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
partialruby is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with partialruby. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "rubygems"
|
22
|
+
require "ruby_parser"
|
23
|
+
|
24
|
+
module PartialRuby
|
25
|
+
|
26
|
+
def self.eval(code, b_)
|
27
|
+
c = PureRubyContext.new
|
28
|
+
|
29
|
+
parser = RubyParser.new
|
30
|
+
c.run(parser.parse(code), Frame.new(b_, b_.eval("self")) )
|
31
|
+
end
|
32
|
+
|
33
|
+
class Frame
|
34
|
+
attr_reader :_binding
|
35
|
+
attr_reader :_self
|
36
|
+
attr_reader :locals
|
37
|
+
|
38
|
+
def initialize(b, _self)
|
39
|
+
@_binding = b
|
40
|
+
@_self = _self
|
41
|
+
@locals = Hash.new
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Context
|
46
|
+
def object_ref(obj)
|
47
|
+
"ObjectSpace._id2ref(#{obj.object_id})"
|
48
|
+
end
|
49
|
+
|
50
|
+
def ruby_emul(tree)
|
51
|
+
nodetype = tree.first
|
52
|
+
send("ruby_emul_"+nodetype.to_s, tree)
|
53
|
+
end
|
54
|
+
|
55
|
+
def emul(tree)
|
56
|
+
begin
|
57
|
+
# first, try to emul the node
|
58
|
+
return ruby_emul(tree)
|
59
|
+
rescue NoMethodError => e
|
60
|
+
if tree
|
61
|
+
"#{object_ref self}.run(#{object_ref tree}, PartialRuby::Frame.new(binding,self) )"
|
62
|
+
else
|
63
|
+
"nil; "
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def run(tree, frame)
|
69
|
+
return nil unless tree
|
70
|
+
|
71
|
+
nodetype = tree.first
|
72
|
+
|
73
|
+
code = nil
|
74
|
+
begin
|
75
|
+
# first, try to emul the node
|
76
|
+
code = ruby_emul(tree)
|
77
|
+
rescue NoMethodError => e
|
78
|
+
end
|
79
|
+
|
80
|
+
if code then
|
81
|
+
eval(code, frame._binding)
|
82
|
+
else
|
83
|
+
send("handle_node_"+nodetype.to_s, tree, frame)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class PureRubyContext < Context
|
89
|
+
|
90
|
+
# def handle_node_scope(tree, frame)
|
91
|
+
# run(tree[1], frame)
|
92
|
+
# end
|
93
|
+
|
94
|
+
def ruby_emul_nil(tree)
|
95
|
+
"(nil)"
|
96
|
+
end
|
97
|
+
|
98
|
+
def ruby_emul_scope(tree)
|
99
|
+
emul tree[1]
|
100
|
+
end
|
101
|
+
|
102
|
+
def ruby_emul_block(tree)
|
103
|
+
last = nil
|
104
|
+
|
105
|
+
code = ""
|
106
|
+
tree[1..-1].each do |subtree|
|
107
|
+
code << emul(subtree) << "\n"
|
108
|
+
end
|
109
|
+
|
110
|
+
code
|
111
|
+
end
|
112
|
+
|
113
|
+
def ruby_emul_hash(tree)
|
114
|
+
pairs = Array.new
|
115
|
+
(0..((tree.size - 1) / 2)-1).each do |i|
|
116
|
+
pairs << [ tree[i*2+1], tree[i*2+2] ]
|
117
|
+
end
|
118
|
+
|
119
|
+
"{" + pairs.map{|pair| "(#{emul pair.first})=>(#{emul pair.last} )" }.join(",") + "}"
|
120
|
+
end
|
121
|
+
|
122
|
+
# def handle_node_block(tree, frame)
|
123
|
+
# last = nil
|
124
|
+
# tree[1..-1].each do |subtree|
|
125
|
+
# last = run(subtree, frame)
|
126
|
+
# end
|
127
|
+
|
128
|
+
# last
|
129
|
+
#end
|
130
|
+
|
131
|
+
def ruby_emul_lasgn(tree)
|
132
|
+
varname = tree[1]
|
133
|
+
"#{varname} = ( #{emul(tree[2])} );"
|
134
|
+
end
|
135
|
+
|
136
|
+
def ruby_emul_lvar(tree)
|
137
|
+
varname = tree[1]
|
138
|
+
varname.to_s
|
139
|
+
end
|
140
|
+
|
141
|
+
def ruby_emul_const(tree)
|
142
|
+
tree[1].to_s
|
143
|
+
end
|
144
|
+
|
145
|
+
def ruby_emul_colon3(tree)
|
146
|
+
"::" + tree[1].to_s
|
147
|
+
end
|
148
|
+
|
149
|
+
def ruby_emul_colon2(tree)
|
150
|
+
"#{emul tree[1]}::#{tree[2]}"
|
151
|
+
end
|
152
|
+
|
153
|
+
def ruby_emul_class(tree)
|
154
|
+
classtree = tree[1]
|
155
|
+
subtree = tree[3]
|
156
|
+
|
157
|
+
classname = ""
|
158
|
+
if classtree.instance_of? Symbol then
|
159
|
+
classname = classtree
|
160
|
+
else
|
161
|
+
classname = emul classtree
|
162
|
+
end
|
163
|
+
|
164
|
+
return ("
|
165
|
+
class #{classname}
|
166
|
+
#{emul subtree}
|
167
|
+
end
|
168
|
+
")
|
169
|
+
end
|
170
|
+
|
171
|
+
def ruby_emul_defs(tree)
|
172
|
+
methodname = tree[2]
|
173
|
+
args = tree[3]
|
174
|
+
"def (#{emul tree[1]}).#{methodname}(#{args[1..-1].map(&:to_s).join(",")})
|
175
|
+
#{emul tree[4]}
|
176
|
+
end
|
177
|
+
"
|
178
|
+
end
|
179
|
+
|
180
|
+
def ruby_emul_defn(tree)
|
181
|
+
method_name = tree[1]
|
182
|
+
args = tree[2]
|
183
|
+
impl = tree[3][1]
|
184
|
+
|
185
|
+
"def #{method_name}(#{args[1..-1].map(&:to_s).join(",")})
|
186
|
+
#{emul impl}
|
187
|
+
end
|
188
|
+
"
|
189
|
+
end
|
190
|
+
|
191
|
+
def ruby_emul_lit(tree)
|
192
|
+
obj = tree[1]
|
193
|
+
if obj.instance_of? Symbol or obj.instance_of? Fixnum or obj == nil or obj == true or obj == false
|
194
|
+
"(#{obj.inspect})"
|
195
|
+
else
|
196
|
+
"(#{object_ref tree[1]})"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def ruby_emul_str(tree)
|
201
|
+
"(#{tree[1].inspect})"
|
202
|
+
end
|
203
|
+
|
204
|
+
def ruby_emul_cdecl(tree)
|
205
|
+
|
206
|
+
if tree[1].instance_of? Sexp
|
207
|
+
"(#{emul tree[1]} = #{emul tree[2]})"
|
208
|
+
else
|
209
|
+
"(#{tree[1]} = #{emul tree[2]})"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def ruby_emul_dstr(tree)
|
214
|
+
firststr = tree[1]
|
215
|
+
retstr = firststr
|
216
|
+
tree[2..-1].each do |subtree|
|
217
|
+
|
218
|
+
subtreetype = subtree[0]
|
219
|
+
|
220
|
+
if subtreetype == :evstr
|
221
|
+
retstr << "\#{(#{emul subtree[1]})}"
|
222
|
+
else
|
223
|
+
retstr << "\#{(#{emul subtree})}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
'"' + retstr + '"'
|
228
|
+
end
|
229
|
+
|
230
|
+
def ruby_emul_array(tree)
|
231
|
+
"[" + tree[1..-1].map{ |subtree| "(" + emul(subtree) + ")" }.join(",") + "]"
|
232
|
+
end
|
233
|
+
|
234
|
+
def ruby_emul_self(tree)
|
235
|
+
"(self)"
|
236
|
+
end
|
237
|
+
|
238
|
+
def ruby_emul_true(tree)
|
239
|
+
"true"
|
240
|
+
end
|
241
|
+
|
242
|
+
def ruby_emul_false(tree)
|
243
|
+
"false"
|
244
|
+
end
|
245
|
+
|
246
|
+
def ruby_emul_if(tree)
|
247
|
+
"if (#{emul tree[1]}); (#{emul tree[2]}) else (#{emul tree[3]}) end"
|
248
|
+
end
|
249
|
+
|
250
|
+
def ruby_emul_while(tree)
|
251
|
+
"while (#{emul tree[1]}); (#{emul tree[2]}); end "
|
252
|
+
end
|
253
|
+
|
254
|
+
def process_args(tree)
|
255
|
+
nodetype = tree[0]
|
256
|
+
if nodetype == :lasgn
|
257
|
+
tree.last.to_s
|
258
|
+
elsif nodetype == :masgn
|
259
|
+
tree[1][1..-1].map {|subtree|
|
260
|
+
process_args(subtree)
|
261
|
+
}.join(",")
|
262
|
+
elsif nodetype == :splat
|
263
|
+
"*" + process_args(tree.last)
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
def ruby_emul_iter(tree)
|
269
|
+
callnode = tree[1]
|
270
|
+
innernode = tree[3]
|
271
|
+
|
272
|
+
arguments = tree[2]
|
273
|
+
argumentsstr = ""
|
274
|
+
|
275
|
+
if arguments
|
276
|
+
argumentsstr = "|" + process_args(arguments) + "|"
|
277
|
+
end
|
278
|
+
"#{emul callnode} { #{argumentsstr} #{emul innernode} }"
|
279
|
+
end
|
280
|
+
|
281
|
+
def ruby_emul_until(tree)
|
282
|
+
"until (#{emul tree[1]}); (#{emul tree[2]}); end "
|
283
|
+
end
|
284
|
+
|
285
|
+
def ruby_emul_case(tree)
|
286
|
+
str = "case #{emul tree[1]}; "
|
287
|
+
|
288
|
+
tree[2..-2].each do |subtree|
|
289
|
+
matches = subtree[1][1..-1].map{|subsubtree| "(" + emul(subsubtree) + ")" }.join(",")
|
290
|
+
|
291
|
+
str << "when #{matches}; #{emul subtree[2]};"
|
292
|
+
end
|
293
|
+
|
294
|
+
if tree[-1]
|
295
|
+
str << "else; #{emul tree[-1]}; "
|
296
|
+
end
|
297
|
+
|
298
|
+
str << "end; "
|
299
|
+
str
|
300
|
+
end
|
301
|
+
|
302
|
+
def ruby_emul_splat(tree)
|
303
|
+
"*(#{emul(tree[1])})"
|
304
|
+
end
|
305
|
+
|
306
|
+
def ruby_emul_ensure(tree)
|
307
|
+
"begin;
|
308
|
+
#{emul tree[1]}
|
309
|
+
ensure;
|
310
|
+
#{emul tree[2] }
|
311
|
+
end;
|
312
|
+
"
|
313
|
+
end
|
314
|
+
|
315
|
+
def ruby_emul_ivar(tree)
|
316
|
+
"(" + tree[1].to_s + ")"
|
317
|
+
end
|
318
|
+
|
319
|
+
def ruby_emul_iasgn(tree)
|
320
|
+
"(#{tree[1].to_s} = (#{emul tree[2]}))"
|
321
|
+
end
|
322
|
+
|
323
|
+
def ruby_emul_gvar(tree)
|
324
|
+
"(" + tree[1].to_s + ")"
|
325
|
+
end
|
326
|
+
|
327
|
+
def ruby_emul_gasgn(tree)
|
328
|
+
"(#{tree[1].to_s} = (#{emul tree[2]}))"
|
329
|
+
end
|
330
|
+
|
331
|
+
def ruby_emul_xstr(tree)
|
332
|
+
"`#{tree[1].gsub("`","")}`"
|
333
|
+
end
|
334
|
+
|
335
|
+
def ruby_emul_dxstr(tree)
|
336
|
+
firststr = tree[1]
|
337
|
+
retstr = firststr
|
338
|
+
tree[2..-1].each do |subtree|
|
339
|
+
|
340
|
+
subtreetype = subtree[0]
|
341
|
+
|
342
|
+
if subtreetype == :evstr
|
343
|
+
retstr << "\#{(#{emul subtree[1]})}"
|
344
|
+
else
|
345
|
+
retstr << "\#{(#{emul subtree})}"
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
'`' + retstr + '`'
|
350
|
+
end
|
351
|
+
|
352
|
+
def ruby_emul_yield(tree)
|
353
|
+
|
354
|
+
strargs = tree[1..-1].map{ |subtree|
|
355
|
+
if subtree[0] == :splat
|
356
|
+
"*(" + emul(subtree[1]) + ")"
|
357
|
+
else
|
358
|
+
"(" + emul(subtree) + ")"
|
359
|
+
end
|
360
|
+
}.join(",")
|
361
|
+
|
362
|
+
"(yield(#{strargs}))"
|
363
|
+
end
|
364
|
+
|
365
|
+
def ruby_emul_module(tree)
|
366
|
+
|
367
|
+
if tree[1].instance_of? Symbol
|
368
|
+
modulename = tree[1].to_s
|
369
|
+
else
|
370
|
+
modulename = emul tree[1]
|
371
|
+
end
|
372
|
+
|
373
|
+
"module #{modulename}
|
374
|
+
#{emul tree[2]}
|
375
|
+
end
|
376
|
+
"
|
377
|
+
end
|
378
|
+
|
379
|
+
def ruby_emul_rescue(tree)
|
380
|
+
|
381
|
+
resbody = tree[2][2]
|
382
|
+
|
383
|
+
strresbody = ""
|
384
|
+
if resbody
|
385
|
+
strresbody = emul resbody
|
386
|
+
else
|
387
|
+
strresbody = ""
|
388
|
+
end
|
389
|
+
|
390
|
+
exceptionarray = tree[2][1][1..-1]
|
391
|
+
|
392
|
+
exceptionstrarray = []
|
393
|
+
|
394
|
+
i = 0
|
395
|
+
while i < exceptionarray.size
|
396
|
+
if exceptionarray[i+1]
|
397
|
+
if exceptionarray[i+1][0] == :lasgn
|
398
|
+
exceptionstrarray << "(" + (emul(exceptionarray[i]) + ") => " + exceptionarray[i+1][1].to_s)
|
399
|
+
i = i + 1
|
400
|
+
else
|
401
|
+
exceptionstrarray << "(" + (emul(exceptionarray[i])) + ")"
|
402
|
+
end
|
403
|
+
else
|
404
|
+
exceptionstrarray << "(" + (emul(exceptionarray[i])) + ")"
|
405
|
+
end
|
406
|
+
i = i + 1
|
407
|
+
end
|
408
|
+
|
409
|
+
"begin;
|
410
|
+
#{emul tree[1]}
|
411
|
+
rescue #{exceptionstrarray.join(",")};
|
412
|
+
#{strresbody}
|
413
|
+
end;
|
414
|
+
"
|
415
|
+
end
|
416
|
+
|
417
|
+
def ruby_emul_return(tree)
|
418
|
+
"; return #{emul tree[1]}; "
|
419
|
+
end
|
420
|
+
|
421
|
+
def ruby_emul_and(tree)
|
422
|
+
"(#{emul tree[1]}) and (#{emul tree[2]})"
|
423
|
+
end
|
424
|
+
|
425
|
+
def ruby_emul_or(tree)
|
426
|
+
"(#{emul tree[1]}) or (#{emul tree[2]})"
|
427
|
+
end
|
428
|
+
|
429
|
+
def ruby_emul_not(tree)
|
430
|
+
"not (#{emul tree[1]})"
|
431
|
+
end
|
432
|
+
|
433
|
+
def ruby_emul_call(tree)
|
434
|
+
object_tree = tree[1]
|
435
|
+
method_name = tree[2]
|
436
|
+
|
437
|
+
arglisttree = tree[3]
|
438
|
+
arglist = arglisttree[1..-1]
|
439
|
+
|
440
|
+
argsstr = arglist.
|
441
|
+
map{|subtree|
|
442
|
+
if subtree[0] == :splat
|
443
|
+
emul(subtree)
|
444
|
+
else
|
445
|
+
"(" + emul(subtree) + ")"
|
446
|
+
end
|
447
|
+
}.
|
448
|
+
join(",")
|
449
|
+
|
450
|
+
if (object_tree)
|
451
|
+
if arglist.count == 0
|
452
|
+
"(#{emul(object_tree)}).#{method_name}"
|
453
|
+
else
|
454
|
+
"(#{emul(object_tree)}).#{method_name}(#{argsstr})"
|
455
|
+
end
|
456
|
+
else
|
457
|
+
if arglist.count == 0
|
458
|
+
"#{method_name}"
|
459
|
+
else
|
460
|
+
"#{method_name}(#{argsstr})"
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
#X.new.foo
|
468
|
+
end
|