rubinius-compiler 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4f7a4f90b65396c5b6a411d0dba6d2c27fac75c0
4
+ data.tar.gz: 31e27d1a8b667740b398c6456b37dd1e8e3b694f
5
+ SHA512:
6
+ metadata.gz: e0278293e994de4801017219e759a19763e45454775231657a7df08ca28498fe56cece97f306f011138954041e590512fc8d85b18914eac9c79f8555748f7c9e
7
+ data.tar.gz: 0ed9518ee5010a0834630b6fb91b85b013515ce1eb2ded814962492aceb24533640aba5788f341b3f35b23eacaf538ab433d2c207dc6f17a55f84a4e6d93cbfc
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rubinius-compiler.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rubinius::Compiler
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rubinius-compiler'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rubinius-compiler
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,11 @@
1
+ require "rubinius/compiler/compiler"
2
+ require "rubinius/compiler/stages"
3
+ require "rubinius/compiler/locals"
4
+ require "rubinius/compiler/generator_methods"
5
+ require "rubinius/compiler/generator"
6
+ require "rubinius/compiler/iseq"
7
+ require "rubinius/compiler/opcodes"
8
+ require "rubinius/compiler/compiled_file"
9
+ require "rubinius/compiler/evaluator"
10
+ require "rubinius/compiler/printers"
11
+ require "rubinius/compiler/runtime"
@@ -0,0 +1,338 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ ##
5
+ # A decode for the .rbc file format.
6
+
7
+ class CompiledFile
8
+ ##
9
+ # Create a CompiledFile with +magic+ bytes, +signature+, and +version+.
10
+ # The optional +stream+ is used to lazy load the body.
11
+
12
+ def initialize(magic, signature, version, stream=nil)
13
+ @magic = magic
14
+ @signature = signature
15
+ @version = version
16
+ @stream = stream
17
+ @data = nil
18
+ end
19
+
20
+ attr_reader :magic
21
+ attr_reader :signature
22
+ attr_reader :version
23
+ attr_reader :stream
24
+
25
+ ##
26
+ # From a stream-like object +stream+ load the data in and return a
27
+ # CompiledFile object.
28
+
29
+ def self.load(stream)
30
+ raise IOError, "attempted to load nil stream" unless stream
31
+
32
+ magic = stream.gets.strip
33
+ signature = Integer(stream.gets.strip)
34
+ version = Integer(stream.gets.strip)
35
+
36
+ return new(magic, signature, version, stream)
37
+ end
38
+
39
+ ##
40
+ # Writes the CompiledFile +code+ to +file+.
41
+ def self.dump(code, file, signature, version)
42
+ File.open(file, "wb") do |f|
43
+ new("!RBIX", signature, version).encode_to(f, code)
44
+ end
45
+ rescue SystemCallError
46
+ # just skip writing the compiled file if we don't have permissions
47
+ end
48
+
49
+ ##
50
+ # Encode the contets of this CompiledFile object to +stream+ with
51
+ # a body of +body+. Body use marshalled using CompiledFile::Marshal
52
+
53
+ def encode_to(stream, body)
54
+ stream.puts @magic
55
+ stream.puts @signature.to_s
56
+ stream.puts @version.to_s
57
+
58
+ mar = CompiledFile::Marshal.new
59
+ stream << mar.marshal(body)
60
+ end
61
+
62
+ ##
63
+ # Return the body object by unmarshaling the data
64
+
65
+ def body
66
+ return @data if @data
67
+
68
+ mar = CompiledFile::Marshal.new
69
+ @data = mar.unmarshal(stream)
70
+ end
71
+
72
+ ##
73
+ # A class used to convert an CompiledCode to and from
74
+ # a String.
75
+
76
+ class Marshal
77
+
78
+ ##
79
+ # Read all data from +stream+ and invoke unmarshal_data
80
+
81
+ def unmarshal(stream)
82
+ if stream.kind_of? String
83
+ str = stream
84
+ else
85
+ str = stream.read
86
+ end
87
+
88
+ @start = 0
89
+ @size = str.size
90
+ @data = str.data
91
+
92
+ unmarshal_data
93
+ end
94
+
95
+ ##
96
+ # Process a stream object +stream+ as as marshalled data and
97
+ # return an object representation of it.
98
+
99
+ def unmarshal_data
100
+ kind = next_type
101
+ case kind
102
+ when 116 # ?t
103
+ return true
104
+ when 102 # ?f
105
+ return false
106
+ when 110 # ?n
107
+ return nil
108
+ when 73 # ?I
109
+ return next_string.to_i(16)
110
+ when 100 # ?d
111
+ str = next_string.chop
112
+
113
+ # handle the special NaN, Infinity and -Infinity differently
114
+ if str[0] == ?\ # leading space
115
+ x = str.to_f
116
+ e = str[-5..-1].to_i
117
+
118
+ # This is necessary because (2**1024).to_f yields Infinity
119
+ if e == 1024
120
+ return x * 2 ** 512 * 2 ** 512
121
+ else
122
+ return x * 2 ** e
123
+ end
124
+ else
125
+ case str.downcase
126
+ when "infinity"
127
+ return 1.0 / 0.0
128
+ when "-infinity"
129
+ return -1.0 / 0.0
130
+ when "nan"
131
+ return 0.0 / 0.0
132
+ else
133
+ raise TypeError, "Invalid Float format: #{str}"
134
+ end
135
+ end
136
+ when 115 # ?s
137
+ enc = unmarshal_data
138
+ count = next_string.to_i
139
+ str = next_bytes count
140
+ str.force_encoding enc if enc and defined?(Encoding)
141
+ return str
142
+ when 120 # ?x
143
+ enc = unmarshal_data
144
+ count = next_string.to_i
145
+ str = next_bytes count
146
+ str.force_encoding enc if enc and defined?(Encoding)
147
+ return str.to_sym
148
+ when 99 # ?c
149
+ count = next_string.to_i
150
+ str = next_bytes count
151
+ return str.split("::").inject(Object) { |a,n| a.const_get(n) }
152
+ when 112 # ?p
153
+ count = next_string.to_i
154
+ obj = Rubinius::Tuple.new(count)
155
+ i = 0
156
+ while i < count
157
+ obj[i] = unmarshal_data
158
+ i += 1
159
+ end
160
+ return obj
161
+ when 105 # ?i
162
+ count = next_string.to_i
163
+ seq = Rubinius::InstructionSequence.new(count)
164
+ i = 0
165
+ while i < count
166
+ seq[i] = next_string.to_i
167
+ i += 1
168
+ end
169
+ return seq
170
+ when 69 # ?E
171
+ count = next_string.to_i
172
+ name = next_bytes count
173
+ return Encoding.find(name) if defined?(Encoding)
174
+ when 77 # ?M
175
+ version = next_string.to_i
176
+ if version != 1
177
+ raise "Unknown CompiledCode version #{version}"
178
+ end
179
+ code = Rubinius::CompiledCode.new
180
+ code.metadata = unmarshal_data
181
+ code.primitive = unmarshal_data
182
+ code.name = unmarshal_data
183
+ code.iseq = unmarshal_data
184
+ code.stack_size = unmarshal_data
185
+ code.local_count = unmarshal_data
186
+ code.required_args = unmarshal_data
187
+ code.post_args = unmarshal_data
188
+ code.total_args = unmarshal_data
189
+ code.splat = unmarshal_data
190
+ code.literals = unmarshal_data
191
+ code.lines = unmarshal_data
192
+ code.file = unmarshal_data
193
+ code.local_names = unmarshal_data
194
+ return code
195
+ else
196
+ raise "Unknown type '#{kind.chr}'"
197
+ end
198
+ end
199
+
200
+ private :unmarshal_data
201
+
202
+ ##
203
+ # Returns the next character in _@data_ as a Fixnum.
204
+ #--
205
+ # The current format uses a one-character type indicator
206
+ # followed by a newline. If that format changes, this
207
+ # will break and we'll fix it.
208
+ #++
209
+ def next_type
210
+ chr = @data[@start]
211
+ @start += 2
212
+ chr
213
+ end
214
+
215
+ private :next_type
216
+
217
+ ##
218
+ # Returns the next string in _@data_ including the trailing
219
+ # "\n" character.
220
+ def next_string
221
+ count = @data.locate "\n", @start, @size
222
+ count = @size unless count
223
+ str = String.from_bytearray @data, @start, count - @start
224
+ @start = count
225
+ str
226
+ end
227
+
228
+ private :next_string
229
+
230
+ ##
231
+ # Returns the next _count_ bytes in _@data_, skipping the
232
+ # trailing "\n" character.
233
+ def next_bytes(count)
234
+ str = String.from_bytearray @data, @start, count
235
+ @start += count + 1
236
+ str
237
+ end
238
+
239
+ private :next_bytes
240
+
241
+ ##
242
+ # For object +val+, return a String represetation.
243
+
244
+ def marshal(val)
245
+ case val
246
+ when TrueClass
247
+ "t\n"
248
+ when FalseClass
249
+ "f\n"
250
+ when NilClass
251
+ "n\n"
252
+ when Fixnum, Bignum
253
+ "I\n#{val.to_s(16)}\n"
254
+ when String
255
+ if defined?(Encoding)
256
+ # We manually construct the Encoding data to avoid recursion
257
+ # marshaling an Encoding name as a String.
258
+ name = val.encoding.name
259
+ enc_name = "E\n#{name.bytesize}\n#{name}\n"
260
+ else
261
+ # The kernel code is all US-ASCII. When building melbourne for 1.8
262
+ # Ruby, we fake a bunch of encoding stuff so force US-ASCII here.
263
+ enc_name = "E\n8\nUS-ASCII\n"
264
+ end
265
+
266
+ "s\n#{enc_name}#{val.bytesize}\n#{val}\n"
267
+ when Symbol
268
+ s = val.to_s
269
+ if defined?(Encoding)
270
+ # We manually construct the Encoding data to avoid recursion
271
+ # marshaling an Encoding name as a String.
272
+ name = s.encoding.name
273
+ enc_name = "E\n#{name.bytesize}\n#{name}\n"
274
+ else
275
+ # The kernel code is all US-ASCII. When building melbourne for 1.8
276
+ # Ruby, we fake a bunch of encoding stuff so force US-ASCII here.
277
+ enc_name = "E\n8\nUS-ASCII\n"
278
+ end
279
+
280
+ "x\n#{enc_name}#{s.bytesize}\n#{s}\n"
281
+ when Rubinius::Tuple
282
+ str = "p\n#{val.size}\n"
283
+ val.each do |ele|
284
+ data = marshal(ele)
285
+ data.force_encoding(str.encoding) if defined?(Encoding)
286
+ str.append data
287
+ end
288
+ str
289
+ when Float
290
+ str = "d\n"
291
+ if val.infinite?
292
+ str.append "-" if val < 0.0
293
+ str.append "Infinity"
294
+ elsif val.nan?
295
+ str.append "NaN"
296
+ else
297
+ str.append " %+.54f %5d" % Math.frexp(val)
298
+ end
299
+ str.append "\n"
300
+ when Rubinius::InstructionSequence
301
+ str = "i\n#{val.size}\n"
302
+ val.opcodes.each do |op|
303
+ unless op.kind_of?(Fixnum)
304
+ raise TypeError, "InstructionSequence contains non Fixnum: #{op.inspect}"
305
+ end
306
+ str.append "#{op}\n"
307
+ end
308
+ str
309
+ when Rubinius::CompiledCode
310
+ str = "M\n1\n"
311
+ str.append marshal(val.metadata)
312
+ str.append marshal(val.primitive)
313
+ str.append marshal(val.name)
314
+ str.append marshal(val.iseq)
315
+ str.append marshal(val.stack_size)
316
+ str.append marshal(val.local_count)
317
+ str.append marshal(val.required_args)
318
+ str.append marshal(val.post_args)
319
+ str.append marshal(val.total_args)
320
+ str.append marshal(val.splat)
321
+ str.append marshal(val.literals)
322
+ str.append marshal(val.lines)
323
+ str.append marshal(val.file)
324
+ str.append marshal(val.local_names)
325
+ str
326
+ else
327
+ if val.respond_to? :rbx_marshal_constant
328
+ name = StringValue(val.rbx_marshal_constant)
329
+ "c\n#{name.size}\n#{name}\n"
330
+ else
331
+ raise ArgumentError, "Unknown type #{val.class}: #{val.inspect}"
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
337
+ end
338
+
@@ -0,0 +1,377 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+
5
+ class CompileError < RuntimeError
6
+ end
7
+
8
+ class Compiler
9
+ attr_accessor :parser, :generator, :encoder, :packager, :writer
10
+
11
+ def self.compiler_error(msg, orig)
12
+ if defined?(RUBY_ENGINE) and RUBY_ENGINE == "rbx"
13
+ raise CompileError, msg, orig
14
+ else
15
+ orig.message.replace("#{orig.message} - #{msg}")
16
+ raise orig
17
+ end
18
+ end
19
+
20
+ if RBC_DB = Rubinius::Config['rbc.db']
21
+ def self.compiled_name(file)
22
+ full = "#{File.expand_path(file)}#{Rubinius::RUBY_LIB_VERSION}"
23
+ hash = Rubinius.invoke_primitive :sha1_hash, full
24
+ dir = hash[0,2]
25
+
26
+ "#{RBC_DB}/#{dir}/#{hash}"
27
+ end
28
+ else
29
+ def self.compiled_cache_writable?(db, dir)
30
+ File.owned?(db) or File.owned?(dir)
31
+ end
32
+
33
+ def self.compiled_name(file)
34
+ name = File.expand_path file
35
+
36
+ # If the file we are compiling is in a subdirectory of the current
37
+ # working directory when Rubinius is started, try to cache the
38
+ # compiled code in <cwd>/.rbx if:
39
+ #
40
+ # 1. <cwd>/.rbx exists and is owned by the process user
41
+ # OR
42
+ # 2. if <cwd> is owned by the process user
43
+ #
44
+ # Otherwise, try to cache the compiled code in ~/.rbx if:
45
+ #
46
+ # 1. ~/.rbx exists and is owned by the process user
47
+ # OR
48
+ # 2. ~/ is owned by the process user
49
+
50
+ unless @db
51
+ dir = Rubinius::OS_STARTUP_DIR
52
+ db = "#{dir}/.rbx"
53
+ unless name.prefix?(dir) and compiled_cache_writable?(db, dir)
54
+ # Yes, this retarded shit is necessary because people actually
55
+ # run under fucked environments with no HOME set.
56
+ return unless ENV["HOME"]
57
+
58
+ dir = File.expand_path "~/"
59
+ db = "#{dir}/.rbx"
60
+ return unless compiled_cache_writable?(db, dir)
61
+ end
62
+ @db = db
63
+ end
64
+
65
+ full = "#{name}#{Rubinius::RUBY_LIB_VERSION}"
66
+ hash = Rubinius.invoke_primitive :sha1_hash, full
67
+
68
+ "#{@db}/#{hash[0, 2]}/#{hash}"
69
+ end
70
+ end
71
+
72
+ def self.compile(file, output=nil, line=1, transforms=:default)
73
+ compiler = new :file, :compiled_file
74
+
75
+ parser = compiler.parser
76
+ parser.root AST::Script
77
+
78
+ if transforms.kind_of? Array
79
+ transforms.each { |t| parser.enable_category t }
80
+ else
81
+ parser.enable_category transforms
82
+ end
83
+
84
+ parser.input file, line
85
+
86
+ writer = compiler.writer
87
+ writer.version = Rubinius::RUBY_LIB_VERSION
88
+ writer.name = output ? output : compiled_name(file)
89
+
90
+ begin
91
+ compiler.run
92
+ rescue SyntaxError => e
93
+ raise e
94
+ rescue Exception => e
95
+ compiler_error "Error trying to compile #{file}", e
96
+ end
97
+
98
+ end
99
+
100
+ # Match old compiler's signature
101
+ def self.compile_file_old(file, flags=nil)
102
+ compile_file file, 1
103
+ end
104
+
105
+ def self.compile_file(file, line=1)
106
+ compiler = new :file, :compiled_code
107
+
108
+ parser = compiler.parser
109
+ parser.root AST::Script
110
+ parser.default_transforms
111
+ parser.input file, line
112
+
113
+ begin
114
+ compiler.run
115
+ rescue Exception => e
116
+ compiler_error "Error trying to compile #{file}", e
117
+ end
118
+ end
119
+
120
+ def self.compile_string(string, file="(eval)", line=1)
121
+ compiler = new :string, :compiled_code
122
+
123
+ parser = compiler.parser
124
+ parser.root AST::Script
125
+ parser.default_transforms
126
+ parser.input string, file, line
127
+
128
+ compiler.run
129
+ end
130
+
131
+ class LRUCache
132
+ class Entry
133
+ attr_reader :hits, :key
134
+ attr_accessor :value, :next_entry, :prev_entry
135
+
136
+ def initialize(key, value)
137
+ @key = key
138
+ @value = value
139
+ @hits = 0
140
+ @next_entry = nil
141
+ @prev_entry = nil
142
+ end
143
+
144
+ def insert_after(entry)
145
+ nxt = entry.next_entry
146
+
147
+ @prev_entry = entry
148
+ @next_entry = nxt
149
+
150
+ entry.next_entry = self
151
+ nxt.prev_entry = self if nxt
152
+ end
153
+
154
+ def insert_before(entry)
155
+ prev = entry.prev_entry
156
+
157
+ @prev_entry = prev
158
+ @next_entry = entry
159
+
160
+ entry.prev_entry = self
161
+ prev.next_entry = self if prev
162
+ end
163
+
164
+ def detach!
165
+ @next_entry.prev_entry = @prev_entry if @next_entry
166
+ @prev_entry.next_entry = @next_entry if @prev_entry
167
+
168
+ @next_entry = nil
169
+ @prev_entry = nil
170
+ end
171
+
172
+ def become_first!
173
+ @prev_entry = nil
174
+ end
175
+
176
+ def inc!
177
+ @hits += 1
178
+ end
179
+ end
180
+
181
+ def initialize(total)
182
+ @cache = {}
183
+ @total = total
184
+ @current = 0
185
+
186
+ @head = Entry.new(nil, nil)
187
+ @tail = Entry.new(nil, nil)
188
+
189
+ @tail.insert_after(@head)
190
+
191
+ @misses = 0
192
+ end
193
+
194
+ attr_reader :current, :misses
195
+
196
+ def clear!
197
+ Rubinius.synchronize(self) do
198
+ @cache = {}
199
+ @current = 0
200
+
201
+ @head = Entry.new(nil, nil, -1)
202
+ @tail = Entry.new(nil, nil, -2)
203
+
204
+ @tail.insert_after(@head)
205
+ end
206
+ end
207
+
208
+ def explain
209
+ entry = @head.next_entry
210
+ while entry != @tail
211
+ str, layout = entry.key
212
+ puts "hits: #{entry.hits}"
213
+ puts "layout: #{layout.inspect}"
214
+ puts "<STRING>"
215
+ puts str
216
+ puts "</STRING>"
217
+
218
+ entry = entry.next_entry
219
+ end
220
+ end
221
+
222
+ def retrieve(key)
223
+ Rubinius.synchronize(self) do
224
+ if entry = @cache[key]
225
+ entry.inc!
226
+
227
+ entry.detach!
228
+ entry.insert_before @tail
229
+
230
+ return entry.value
231
+ end
232
+
233
+ @misses += 1
234
+
235
+ nil
236
+ end
237
+ end
238
+
239
+ def set(key, value)
240
+ Rubinius.synchronize(self) do
241
+ if entry = @cache[key]
242
+ entry.value = value
243
+
244
+ entry.detach!
245
+ entry.insert_before @tail
246
+
247
+ return value
248
+ end
249
+
250
+ if @current == @total
251
+ entry = @head.next_entry
252
+
253
+ entry.detach!
254
+
255
+ @cache.delete entry.key
256
+ else
257
+ @current += 1
258
+ end
259
+
260
+ entry = Entry.new(key, value)
261
+
262
+ entry.insert_before @tail
263
+
264
+ @cache[key] = entry
265
+ end
266
+ end
267
+ end
268
+
269
+ total = Rubinius::Config['eval.cache']
270
+
271
+ case total
272
+ when Fixnum
273
+ if total == 0
274
+ @eval_cache = nil
275
+ else
276
+ @eval_cache = LRUCache.new(total)
277
+ end
278
+ when false
279
+ @eval_cache = nil
280
+ else
281
+ @eval_cache = LRUCache.new(50)
282
+ end
283
+
284
+ def self.eval_cache
285
+ @eval_cache
286
+ end
287
+
288
+ def self.compile_eval(string, variable_scope, file="(eval)", line=1)
289
+ if ec = @eval_cache
290
+ layout = variable_scope.local_layout
291
+ if code = ec.retrieve([string, layout, line])
292
+ return code
293
+ end
294
+ end
295
+
296
+ compiler = new :eval, :compiled_code
297
+
298
+ parser = compiler.parser
299
+ parser.root AST::EvalExpression
300
+ parser.default_transforms
301
+ parser.input string, file, line
302
+
303
+ compiler.generator.variable_scope = variable_scope
304
+
305
+ code = compiler.run
306
+
307
+ code.add_metadata :for_eval, true
308
+
309
+ if ec and parser.should_cache?
310
+ ec.set([string.dup, layout, line], code)
311
+ end
312
+
313
+ return code
314
+ end
315
+
316
+ def self.construct_block(string, binding, file="(eval)", line=1)
317
+ code = compile_eval string, binding.variables, file, line
318
+
319
+ code.scope = binding.constant_scope
320
+ code.name = binding.variables.method.name
321
+
322
+ # This has to be setup so __FILE__ works in eval.
323
+ script = Rubinius::CompiledCode::Script.new(code, file, true)
324
+ script.eval_source = string
325
+
326
+ code.scope.script = script
327
+
328
+ be = Rubinius::BlockEnvironment.new
329
+ be.under_context binding.variables, code
330
+
331
+ # Pass the BlockEnvironment this binding was created from
332
+ # down into the new BlockEnvironment we just created.
333
+ # This indicates the "declaration trace" to the stack trace
334
+ # mechanisms, which can be different from the "call trace"
335
+ # in the case of, say: eval("caller", a_proc_instance)
336
+ if binding.from_proc?
337
+ be.proc_environment = binding.proc_environment
338
+ end
339
+
340
+ return be
341
+ end
342
+
343
+ def self.compile_test_bytecode(string, transforms)
344
+ compiler = new :string, :bytecode
345
+
346
+ parser = compiler.parser
347
+ parser.root AST::Snippet
348
+ parser.input string
349
+ transforms.each { |x| parser.enable_transform x }
350
+
351
+ compiler.generator.processor Rubinius::TestGenerator
352
+
353
+ compiler.run
354
+ end
355
+
356
+ def self.compile_test_bytecode_19(string, transforms)
357
+ compiler = new :string, :bytecode
358
+
359
+ parser = compiler.parser
360
+ parser.root AST::Snippet
361
+ parser.input string
362
+ transforms.each { |x| parser.enable_transform x }
363
+
364
+ compiler.generator.processor TestGenerator
365
+
366
+ compiler.run
367
+ end
368
+
369
+ def initialize(from, to)
370
+ @start = Stages[from].new self, to
371
+ end
372
+
373
+ def run
374
+ @start.run
375
+ end
376
+ end
377
+ end