duby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +68 -0
  3. data/README.txt +31 -0
  4. data/Rakefile +37 -0
  5. data/bin/duby +9 -0
  6. data/bin/dubyc +9 -0
  7. data/bin/dubyp +9 -0
  8. data/examples/appengine/src/com/google/appengine/ext/duby/db/Model.duby +132 -0
  9. data/examples/appengine/src/com/ribrdb/DubyApp.duby +28 -0
  10. data/examples/bench_fractal.duby +57 -0
  11. data/examples/construction.duby +8 -0
  12. data/examples/edb.duby +3 -0
  13. data/examples/fib.duby +24 -0
  14. data/examples/fields.duby +22 -0
  15. data/examples/java_thing.duby +13 -0
  16. data/examples/simple_class.duby +12 -0
  17. data/examples/swing.duby +20 -0
  18. data/examples/tak.duby +15 -0
  19. data/javalib/JRubyParser.jar +0 -0
  20. data/lib/duby.rb +170 -0
  21. data/lib/duby/ast.rb +340 -0
  22. data/lib/duby/ast/call.rb +73 -0
  23. data/lib/duby/ast/class.rb +145 -0
  24. data/lib/duby/ast/flow.rb +328 -0
  25. data/lib/duby/ast/intrinsics.rb +46 -0
  26. data/lib/duby/ast/literal.rb +93 -0
  27. data/lib/duby/ast/local.rb +77 -0
  28. data/lib/duby/ast/method.rb +187 -0
  29. data/lib/duby/ast/structure.rb +44 -0
  30. data/lib/duby/ast/type.rb +93 -0
  31. data/lib/duby/c/compiler.rb +134 -0
  32. data/lib/duby/compiler.rb +261 -0
  33. data/lib/duby/jvm/compiler.rb +684 -0
  34. data/lib/duby/jvm/method_lookup.rb +185 -0
  35. data/lib/duby/jvm/source_compiler.rb +516 -0
  36. data/lib/duby/jvm/source_generator/builder.rb +368 -0
  37. data/lib/duby/jvm/source_generator/loops.rb +132 -0
  38. data/lib/duby/jvm/source_generator/precompile.rb +154 -0
  39. data/lib/duby/jvm/source_generator/typer.rb +11 -0
  40. data/lib/duby/jvm/typer.rb +118 -0
  41. data/lib/duby/jvm/types.rb +326 -0
  42. data/lib/duby/jvm/types/basic_types.rb +18 -0
  43. data/lib/duby/jvm/types/boolean.rb +11 -0
  44. data/lib/duby/jvm/types/factory.rb +151 -0
  45. data/lib/duby/jvm/types/floats.rb +70 -0
  46. data/lib/duby/jvm/types/integers.rb +110 -0
  47. data/lib/duby/jvm/types/intrinsics.rb +157 -0
  48. data/lib/duby/jvm/types/literals.rb +82 -0
  49. data/lib/duby/jvm/types/methods.rb +344 -0
  50. data/lib/duby/jvm/types/number.rb +92 -0
  51. data/lib/duby/nbcompiler.rb +29 -0
  52. data/lib/duby/old/compiler_old.rb +845 -0
  53. data/lib/duby/old/declaration.rb +72 -0
  54. data/lib/duby/old/mapper.rb +72 -0
  55. data/lib/duby/old/signature.rb +52 -0
  56. data/lib/duby/old/typer_old.rb +163 -0
  57. data/lib/duby/plugin/edb.rb +25 -0
  58. data/lib/duby/plugin/java.rb +42 -0
  59. data/lib/duby/plugin/math.rb +84 -0
  60. data/lib/duby/transform.rb +908 -0
  61. data/lib/duby/typer.rb +359 -0
  62. data/test/test_ast.rb +391 -0
  63. data/test/test_compilation.rb +98 -0
  64. data/test/test_java_typer.rb +199 -0
  65. data/test/test_javac_compiler.rb +57 -0
  66. data/test/test_jvm_compiler.rb +1459 -0
  67. data/test/test_math_plugin.rb +87 -0
  68. data/test/test_typer.rb +246 -0
  69. metadata +155 -0
@@ -0,0 +1,185 @@
1
+ module Duby
2
+ module JVM
3
+ module MethodLookup
4
+ # dummy log; it's expected the inclusion target will have it
5
+ def log(msg); end
6
+
7
+ # def jvm_type(type)
8
+ # return type if type.kind_of? Java::JavaClass
9
+ # return type.jvm_type
10
+ # end
11
+ #
12
+ # def convert_params(params)
13
+ # params.map {|param| jvm_type(param)}
14
+ # end
15
+
16
+ def find_method(mapped_type, name, mapped_params, meta)
17
+ # mapped_type = jvm_type(mapped_type)
18
+ # mapped_params = convert_params(mapped_params)
19
+ raise ArgumentError if mapped_params.any? {|p| p.nil?}
20
+ if name == 'new'
21
+ if meta
22
+ name = "<init>"
23
+ constructor = true
24
+ else
25
+ constructor = false
26
+ end
27
+ end
28
+
29
+ begin
30
+ if constructor
31
+ method = mapped_type.constructor(*mapped_params)
32
+ else
33
+ method = mapped_type.java_method(name, *mapped_params)
34
+ end
35
+ rescue NameError
36
+ unless constructor
37
+ # exact args failed, do a deeper search
38
+ log "Failed to locate method #{mapped_type}.#{name}(#{mapped_params})"
39
+
40
+ method = find_jls(mapped_type, name, mapped_params, meta)
41
+ end
42
+ unless method
43
+ log "Failed to locate method #{name}(#{mapped_params}) on #{mapped_type}"
44
+ return nil
45
+ end
46
+ end
47
+
48
+ log "Found method #{method.declaring_class}.#{name}(#{method.argument_types}) from #{mapped_type}"
49
+ return method
50
+ end
51
+
52
+ def find_jls(mapped_type, name, mapped_params, meta)
53
+ # mapped_type = jvm_type(mapped_type)
54
+ # mapped_params = convert_params(mapped_params)
55
+ if meta
56
+ all_methods = mapped_type.declared_class_methods
57
+ else
58
+ all_methods = []
59
+ cls = mapped_type
60
+ while cls
61
+ all_methods += cls.declared_instance_methods
62
+ cls = cls.superclass
63
+ end
64
+ end
65
+ by_name = all_methods.select {|m| m.name == name && mapped_params.size <= m.argument_types.size}
66
+ by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size}
67
+
68
+ phase1_methods = phase1(mapped_params, by_name_and_arity)
69
+
70
+ if phase1_methods.size > 1
71
+ raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{phase1_methods}"
72
+ end
73
+
74
+ phase1_methods[0] ||
75
+ phase2(mapped_params, by_name) ||
76
+ phase3(mapped_params, by_name)
77
+ end
78
+
79
+ def phase1(mapped_params, potentials)
80
+ # cycle through methods looking for more specific matches; gather matches of equal specificity
81
+ methods = potentials.inject([]) do |currents, potential|
82
+ method_params = potential.argument_types
83
+
84
+ # exact match always wins; duplicates not possible
85
+ return [potential] if each_is_exact(mapped_params, method_params)
86
+
87
+ # otherwise, check for potential match and compare to current
88
+ # TODO: missing ambiguity check; picks last method of equal specificity
89
+ if each_is_exact_or_subtype_or_convertible(mapped_params, method_params)
90
+ if currents.size > 0
91
+ if is_more_specific?(potential.argument_types, currents[0].argument_types)
92
+ # potential is better, dump all currents
93
+ currents = [potential]
94
+ elsif is_more_specific?(currents[0].argument_types, potential.argument_types)
95
+ # currents are better, try next potential
96
+ #next
97
+ else
98
+ # equal specificity, append to currents
99
+ currents << potential
100
+ end
101
+ else
102
+ # no previous matches, use potential
103
+ currents = [potential]
104
+ end
105
+ end
106
+
107
+ currents
108
+ end
109
+
110
+ methods
111
+ end
112
+
113
+ def is_more_specific?(potential, current)
114
+ each_is_exact_or_subtype_or_convertible(potential, current)
115
+ end
116
+
117
+ def phase2(mapped_params, potentials)
118
+ nil
119
+ end
120
+
121
+ def phase3(mapped_params, potentials)
122
+ nil
123
+ end
124
+
125
+ def each_is_exact(incoming, target)
126
+ incoming.each_with_index do |in_type, i|
127
+ target_type = target[i]
128
+
129
+ # exact match
130
+ return false unless target_type == in_type
131
+ end
132
+ return true
133
+ end
134
+
135
+ def each_is_exact_or_subtype_or_convertible(incoming, target)
136
+ incoming.each_with_index do |in_type, i|
137
+ target_type = target[i]
138
+
139
+ # exact match
140
+ next if target_type == in_type
141
+
142
+ # primitive is safely convertible
143
+ if target_type.primitive?
144
+ if in_type.primitive?
145
+ next if primitive_convertible? in_type, target_type
146
+ end
147
+ return false
148
+ end
149
+
150
+ # object type is assignable
151
+ return false unless target_type.assignable_from? in_type
152
+ end
153
+ return true
154
+ end
155
+
156
+ BOOLEAN = Java::boolean.java_class
157
+ BYTE = Java::byte.java_class
158
+ SHORT = Java::short.java_class
159
+ CHAR = Java::char.java_class
160
+ INT = Java::int.java_class
161
+ LONG = Java::long.java_class
162
+ FLOAT = Java::float.java_class
163
+ DOUBLE = Java::double.java_class
164
+
165
+ PrimitiveConversions = {
166
+ BOOLEAN => [BOOLEAN],
167
+ BYTE => [BYTE, SHORT, CHAR, INT, LONG, FLOAT, DOUBLE],
168
+ SHORT => [SHORT, INT, LONG, FLOAT, DOUBLE],
169
+ CHAR => [CHAR, INT, LONG, FLOAT, DOUBLE],
170
+ INT => [INT, LONG, FLOAT, DOUBLE],
171
+ LONG => [LONG, DOUBLE],
172
+ FLOAT => [FLOAT, DOUBLE],
173
+ DOUBLE => [DOUBLE]
174
+ }
175
+
176
+ def primitive_convertible?(in_type, target_type)
177
+ if PrimitiveConversions.include? in_type
178
+ PrimitiveConversions[in_type].include?(target_type)
179
+ else
180
+ in_type.convertible_to?(target_type)
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,516 @@
1
+ require 'duby'
2
+ require 'duby/ast'
3
+ require 'duby/jvm/types'
4
+ require 'duby/jvm/compiler'
5
+ require 'duby/jvm/source_generator/builder'
6
+ require 'duby/jvm/source_generator/precompile'
7
+ require 'duby/jvm/source_generator/loops'
8
+
9
+ class String
10
+ def compile(compiler, expression)
11
+ compiler.method.print self if expression
12
+ end
13
+ end
14
+
15
+ module Duby
16
+ module Compiler
17
+ class JavaSource
18
+ JVMTypes = Duby::JVM::Types
19
+ include Duby::Compiler::JVM::JVMLogger
20
+ attr_accessor :filename, :method, :static, :class, :lvalue
21
+
22
+ Operators = [
23
+ '+', '-', '+@', '-@', '/', '%', '*', '<',
24
+ '<=', '==', '!=', '>=', '>',
25
+ '<<', '>>', '>>>', '|', '&', '^', '~'
26
+ ]
27
+ ArrayOps = [
28
+ '[]', '[]=', 'length'
29
+ ]
30
+
31
+ ImplicitReturn = Struct.new(:value)
32
+
33
+ def initialize(filename)
34
+ @filename = File.basename(filename)
35
+ @static = true
36
+ parts = filename.split '/'
37
+ classname = parts.pop.sub /[.].+/, ''
38
+ package = parts.join('.') unless parts.empty?
39
+
40
+ @file = Duby::JavaSource::Builder.new(filename, self)
41
+ #@file.package = package
42
+ @class = @file.public_class(classname)
43
+ end
44
+
45
+ def generate(&block)
46
+ @class.stop
47
+ log "Generating source files..."
48
+ @file.generate do |filename, builder|
49
+ log " #{builder.class_name}"
50
+ if block_given?
51
+ yield filename, builder
52
+ else
53
+ File.open(filename, 'w') {|f| f.write(builder.generate)}
54
+ end
55
+ end
56
+ log "...done!"
57
+ end
58
+
59
+ def define_main(body)
60
+ with :method => @class.main do
61
+ log "Starting main method"
62
+
63
+ @method.start
64
+
65
+ body.compile(self, false)
66
+
67
+ @method.stop
68
+ end
69
+
70
+ log "Main method complete!"
71
+ end
72
+
73
+ def define_method(name, signature, args, body, force_static)
74
+ args = args.args || []
75
+ return_type = signature[:return]
76
+ exceptions = signature[:throws] || []
77
+ if @static || force_static
78
+ method = @class.public_static_method(name.to_s, return_type, exceptions, *args)
79
+ else
80
+ if name == "initialize"
81
+ method = @class.public_constructor(exceptions, *args)
82
+ else
83
+ method = @class.public_method(name.to_s, return_type, exceptions, *args)
84
+ end
85
+ end
86
+
87
+ with :method => method, :static => @static || force_static do
88
+ log "Starting new method #{name}"
89
+
90
+ @method.start
91
+
92
+ unless @method.type.nil? || @method.type.void?
93
+ self.return(ImplicitReturn.new(body))
94
+ else
95
+ body.compile(self, false) if body
96
+ end
97
+
98
+ log "Method #{name} complete!"
99
+ @method.stop
100
+ end
101
+ end
102
+
103
+ def return(node)
104
+ if @method.type.nil? || @method.type.void?
105
+ @method.puts 'return;'
106
+ return
107
+ end
108
+ if node.value.expr?(self)
109
+ @method.print 'return '
110
+ node.value.compile(self, true)
111
+ @method.puts ';'
112
+ else
113
+ store_value('return ', node.value)
114
+ end
115
+ end
116
+
117
+ def _raise(node)
118
+ if node.expr?(self)
119
+ @method.print 'throw '
120
+ node.compile(self, true)
121
+ @method.puts ';'
122
+ else
123
+ store_value('throw ', node)
124
+ end
125
+ end
126
+
127
+ def rescue(node, expression)
128
+ @method.block 'try' do
129
+ maybe_store(node.body, expression)
130
+ end
131
+ node.clauses.each do |clause|
132
+ clause.types.each do |type|
133
+ name = clause.name || 'tmp$ex'
134
+ @method.block "catch (#{type.to_source} #{name})" do
135
+ maybe_store(clause.body, expression)
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ def ensure(node, expression)
142
+ @method.block 'try' do
143
+ maybe_store(node.body, expression)
144
+ end
145
+ @method.block 'finally' do
146
+ node.clause.compile(self, false)
147
+ end
148
+ end
149
+
150
+ def line(num)
151
+ end
152
+
153
+ def declare_local(name, type)
154
+ @method.declare_local(type, name)
155
+ end
156
+
157
+ def declare_field(name, type)
158
+ @class.declare_field(name, type, @static)
159
+ end
160
+
161
+ def local(name, type)
162
+ @method.print name
163
+ end
164
+
165
+ def field(name, type)
166
+ name = name[1..-1]
167
+ declare_field(name, type)
168
+ @method.print "#{this}.#{name}"
169
+ end
170
+
171
+ def this
172
+ @static ? @class.class_name : 'this'
173
+ end
174
+
175
+ def local_assign(name, type, expression, value)
176
+ value = value.precompile(self)
177
+ if method.local?(name)
178
+ @method.print @lvalue if expression
179
+ @method.print "#{name} = "
180
+ value.compile(self, true)
181
+ @method.puts ';'
182
+ else
183
+ @method.declare_local(type, name) do
184
+ value.compile(self, true)
185
+ end
186
+ if expression
187
+ @method.puts "#{@lvalue}#{name};"
188
+ end
189
+ end
190
+ end
191
+
192
+ def field_declare(name, type)
193
+ name = name[1..-1]
194
+ declare_field(name, type)
195
+ end
196
+
197
+ def local_declare(name, type)
198
+ declare_local(name, type)
199
+ end
200
+
201
+ def field_assign(name, type, expression, value)
202
+ name = name[1..-1]
203
+ declare_field(name, type)
204
+ lvalue = "#{@lvalue if expression}#{this}.#{name} = "
205
+ store_value(lvalue, value)
206
+ end
207
+
208
+ def store_value(lvalue, value)
209
+ if value.is_a? String
210
+ @method.puts "#{lvalue}#{value};"
211
+ elsif value.expr?(self)
212
+ @method.print lvalue
213
+ value.compile(self, true)
214
+ @method.puts ';'
215
+ else
216
+ with :lvalue => lvalue do
217
+ value.compile(self, true)
218
+ end
219
+ end
220
+ end
221
+
222
+ def assign(name, value)
223
+ store_value("#{name} = ", value)
224
+ name
225
+ end
226
+
227
+ def maybe_store(value, expression)
228
+ if expression
229
+ store_value(@lvalue, value)
230
+ else
231
+ value.compile(self, false)
232
+ end
233
+ end
234
+
235
+ def body(body, expression)
236
+ # all except the last element in a body of code is treated as a statement
237
+ i, last = 0, body.children.size - 1
238
+ while i < last
239
+ body.children[i].compile(self, false)
240
+ i += 1
241
+ end
242
+ # last element is an expression only if the body is an expression
243
+ maybe_store(body.children[last], expression)
244
+ end
245
+
246
+ def branch_expression(node)
247
+ node.condition.compile(self, true)
248
+ @method.print ' ? ('
249
+ if node.body
250
+ node.body.compile(self, true)
251
+ else
252
+ @method.print @method.init_value(node.inferred_type)
253
+ end
254
+ @method.print ') : ('
255
+ if node.else
256
+ node.else.compile(self, true)
257
+ else
258
+ @method.print @method.init_value(node.inferred_type)
259
+ end
260
+ @method.print ')'
261
+ end
262
+
263
+ def branch(node, expression)
264
+ if expression && node.expr?(self)
265
+ return branch_expression(node)
266
+ end
267
+ predicate = node.condition.predicate.precompile(self)
268
+ @method.print 'if ('
269
+ predicate.compile(self, true)
270
+ @method.block ")" do
271
+ if node.body
272
+ maybe_store(node.body, expression)
273
+ elsif expression
274
+ store_value(@lvalue, @method.init_value(node.inferred_type))
275
+ end
276
+ end
277
+ if node.else || expression
278
+ @method.block 'else' do
279
+ if node.else
280
+ maybe_store(node.else, expression)
281
+ else
282
+ store_value(@lvalue, @method.init_value(node.inferred_type))
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ def while_loop(loop, expression)
289
+ if loop.redo || !loop.condition.predicate.expr?(self)
290
+ loop = ComplexWhileLoop.new(loop, self)
291
+ else
292
+ loop = SimpleWhileLoop.new(loop, self)
293
+ end
294
+ with(:loop => loop) do
295
+ loop.compile(expression)
296
+ end
297
+ end
298
+
299
+ def for_loop(loop, expression)
300
+ if loop.redo
301
+ loop = RedoableForLoop.new(loop, self)
302
+ else
303
+ loop = SimpleForLoop.new(loop, self)
304
+ end
305
+ with(:loop => loop) do
306
+ loop.compile(expression)
307
+ end
308
+ end
309
+
310
+ def expr?(target, params)
311
+ !([target] + params).any? {|x| x.kind_of? Duby::AST::TempValue}
312
+ end
313
+
314
+ def operator(target, op, params, expression)
315
+ simple = expr?(target, params)
316
+ if expression && !simple
317
+ @method.print @lvalue
318
+ end
319
+ if params.size == 0
320
+ # unary operator
321
+ op = op[0,1]
322
+ @method.print op
323
+ target.compile(self, true)
324
+ else
325
+ @method.print '('
326
+ other = params[0]
327
+ target.compile(self, true)
328
+ @method.print " #{op} "
329
+ other.compile(self, true)
330
+ @method.print ')'
331
+ end
332
+ unless expression && simple
333
+ @method.puts ';'
334
+ end
335
+ end
336
+
337
+ def compile_args(call)
338
+ call.parameters.map do |param|
339
+ param.precompile(self)
340
+ end
341
+ end
342
+
343
+ def self_type
344
+ type = AST::type(@class.name.tr('/', '.'))
345
+ type = type.meta if @static
346
+ type
347
+ end
348
+
349
+ def self_call(call, expression)
350
+ if call.cast?
351
+ args = compile_args(call)
352
+ simple = call.expr?(self)
353
+ @method.print @lvalue if expression && !simple
354
+ @method.print "(#{call.inferred_type.name})("
355
+ args.each{|arg| arg.compile(self, true)}
356
+ @method.print ")"
357
+ @method.puts ';' unless simple && expression
358
+ else
359
+ method_call(this, call, compile_args(call), expression)
360
+ end
361
+ end
362
+
363
+ def call(call, expression)
364
+ if Duby::AST::Constant === call.target
365
+ target = call.target.inferred_type.name
366
+ else
367
+ target = call.target.precompile(self)
368
+ end
369
+ params = compile_args(call)
370
+
371
+ if Operators.include? call.name
372
+ operator(target, call.name, params, expression)
373
+ elsif call.target.inferred_type.array? && ArrayOps.include?(call.name)
374
+ array_op(target, call.name, params, expression)
375
+ elsif call.name == 'nil?'
376
+ operator(target, '==', ['null'], expression)
377
+ else
378
+ method_call(target, call, params, expression)
379
+ end
380
+ end
381
+
382
+ def array_op(target, name, args, expression)
383
+ simple = expr?(target, args)
384
+ index, value = args
385
+ if expression && !simple
386
+ @method.print @lvalue
387
+ end
388
+ target.compile(self, true)
389
+ if name == 'length'
390
+ @method.print '.length'
391
+ else
392
+ @method.print '['
393
+ index.compile(self, true)
394
+ @method.print ']'
395
+ if name == '[]='
396
+ @method.print " = "
397
+ value.compile(self, true)
398
+ end
399
+ end
400
+ unless simple && expression
401
+ @method.puts ';'
402
+ end
403
+ end
404
+
405
+ def break(node)
406
+ @loop.break
407
+ end
408
+
409
+ def next(node)
410
+ @loop.next
411
+ end
412
+
413
+ def redo(node)
414
+ @loop.redo
415
+ end
416
+
417
+ def method_call(target, call, params, expression)
418
+ simple = call.expr?(self)
419
+ method = call.method(self)
420
+ unless simple || method.actual_return_type.void?
421
+ @method.print @lvalue if expression
422
+ end
423
+ if method.constructor?
424
+ @method.print "new "
425
+ target.compile(self, true)
426
+ @method.print '('
427
+ else
428
+ target.compile(self, true)
429
+ @method.print ".#{method.name}("
430
+ end
431
+ params.each_with_index do |param, index|
432
+ @method.print ', ' unless index == 0
433
+ param.compile(self, true)
434
+ end
435
+ if simple && expression
436
+ @method.print ')'
437
+ else
438
+ @method.puts ');'
439
+ end
440
+ if method.actual_return_type.void? && expression
441
+ @method.print @lvalue
442
+ if method.static?
443
+ @method.puts 'null;'
444
+ else
445
+ target.compile(self, true)
446
+ @method.puts ';'
447
+ end
448
+ end
449
+
450
+ end
451
+
452
+ def temp(expression, value=nil)
453
+ assign(@method.tmp(expression.inferred_type), value || expression)
454
+ end
455
+
456
+ def empty_array(type, size)
457
+ sizevar = size.precompile(self)
458
+ @method.print "#{@lvalue unless size.expr?(self)}new #{type.name}["
459
+ sizevar.compile(self, true)
460
+ @method.print ']'
461
+ end
462
+
463
+ def import(short, long)
464
+ end
465
+
466
+ def string(value)
467
+ @method.print value.inspect
468
+ end
469
+
470
+ def boolean(value)
471
+ @method.print value ? 'true' : 'false'
472
+ end
473
+
474
+ def null
475
+ @method.print 'null'
476
+ end
477
+
478
+ def print(node)
479
+ value = node.parameters[0]
480
+ value = value && value.precompile(self)
481
+ if node.println
482
+ @method.print "System.out.println("
483
+ else
484
+ @method.print "System.out.print("
485
+ end
486
+ value.compile(self, true) if value
487
+ @method.puts ');'
488
+ end
489
+
490
+ def define_class(class_def, expression)
491
+ with(:class => class_def.inferred_type.define(@file),
492
+ :static => false) do
493
+ class_def.body.compile(self, false) if class_def.body
494
+
495
+ @class.stop
496
+ end
497
+ end
498
+
499
+ def with(vars)
500
+ orig_values = {}
501
+ begin
502
+ vars.each do |name, new_value|
503
+ name = "@#{name}"
504
+ orig_values[name] = instance_variable_get name
505
+ instance_variable_set name, new_value
506
+ end
507
+ yield
508
+ ensure
509
+ orig_values.each do |name, value|
510
+ instance_variable_set name, value
511
+ end
512
+ end
513
+ end
514
+ end
515
+ end
516
+ end