bitescript 0.0.9 → 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.
@@ -1,3 +1,11 @@
1
+ === 0.1.0 / 2011-11-10
2
+
3
+ be71f3f Re-add old ASM3 versions of everything for backward compat.
4
+ 56e20b0 More fixes for ASM 4.0.
5
+ 9daf504 Fixes for asm 4.0.
6
+ dff922a Added a note about the simple loop example explaining how it works.
7
+ f0ba202 Merge pull request #2 from calavera/master
8
+
1
9
  === 0.0.9 / 2011-07-11
2
10
 
3
11
  62a10d2 Update time format in gemspec
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{bitescript}
5
- s.version = "0.0.9"
5
+ s.version = "0.1.0"
6
6
  s.authors = ["Charles Oliver Nutter", "Ryan Brown"]
7
7
  s.date = Time.now.strftime('%Y-%m-%d')
8
8
  s.description = %q{BiteScript is a Ruby DSL for generating Java bytecode and classes.}
@@ -8,7 +8,7 @@ JClass = java.lang.Class
8
8
  # Our main method, which does one invokedynamic
9
9
  main do
10
10
  # handle for our bootstrap, which binds invokedynamic to a CallSite
11
- bootstrap = mh_invokestatic this, 'bootstrap', CallSite, Lookup, string, MethodType
11
+ bootstrap = h_invokestatic this, 'bootstrap', CallSite, Lookup, string, MethodType
12
12
 
13
13
  ldc 'Hello, invokedynamic!'
14
14
  invokedynamic 'print', [void, string], bootstrap
@@ -1,3 +1,12 @@
1
+ # Simple Loop
2
+ #
3
+ # Run this file to create a SimpleLoop.class file.
4
+ # It takes one argument and prints it out in a loop
5
+ # until you stop the process.
6
+ #
7
+ # ruby examples/simple_loop.rb
8
+ # java SimpleLoop repeatMe
9
+ #
1
10
  require 'bitescript'
2
11
 
3
12
  include BiteScript
@@ -1,9 +1,17 @@
1
1
  $: << File.dirname(__FILE__)
2
- require 'bitescript/asm'
3
- require 'bitescript/signature'
4
- require 'bitescript/bytecode'
5
- require 'bitescript/builder'
6
- require 'bitescript/mirror'
2
+ begin
3
+ require 'bitescript/asm'
4
+ require 'bitescript/signature'
5
+ require 'bitescript/bytecode'
6
+ require 'bitescript/builder'
7
+ require 'bitescript/mirror'
8
+ rescue LoadError
9
+ require 'bitescript/asm3/asm'
10
+ require 'bitescript/asm3/signature'
11
+ require 'bitescript/asm3/bytecode'
12
+ require 'bitescript/asm3/builder'
13
+ require 'bitescript/asm3/mirror'
14
+ end
7
15
 
8
16
  module BiteScript
9
17
  include BiteScript::ASM
@@ -11,6 +19,7 @@ module BiteScript
11
19
  JAVA1_5 = Opcodes::V1_5
12
20
  JAVA1_6 = Opcodes::V1_6
13
21
  JAVA1_7 = Opcodes::V1_7
22
+ JAVA1_8 = defined?(Opcodes::V1_8) ? Opcodes::V1_8 : Opcodes::V1_7
14
23
 
15
24
  class << self
16
25
  attr_accessor :bytecode_version
@@ -23,6 +23,15 @@ module BiteScript
23
23
  java_import asm_package.Opcodes
24
24
  end
25
25
  end
26
+
27
+ # Handle was introduced in ASM 4.0, and is only available to
28
+ # JRuby > 1.6.1
29
+ begin
30
+ java_import asm_package.Handle
31
+ rescue
32
+ raise LoadError, "ASM 4 not available, using ASM3 compat"
33
+ end
34
+
26
35
  java_import asm_package.Label
27
36
  java_import asm_package.Type
28
37
  java_import asm_package.AnnotationVisitor
@@ -35,12 +44,5 @@ module BiteScript
35
44
  java_import asm_package.signature.SignatureReader
36
45
  java_import asm_package.signature.SignatureVisitor
37
46
  java_import asm_package.signature.SignatureWriter
38
-
39
- # MethodHandle was introduced in ASM 4.0, and is only available to
40
- # JRuby > 1.6.1
41
- begin
42
- java_import asm_package.MethodHandle
43
- rescue
44
- end
45
47
  end
46
48
  end
@@ -0,0 +1,46 @@
1
+ require 'java'
2
+
3
+ module BiteScript
4
+ module ASM
5
+ begin
6
+ # try mangled names for the version included with JRuby <=1.6.0.RC2
7
+ java.lang.Class.for_name 'jruby.objectweb.asm.Opcodes'
8
+
9
+ # no error, proceed with mangled name
10
+ asm_package = Java::jruby.objectweb.asm
11
+ java_import asm_package.Opcodes
12
+ rescue Exception
13
+ begin
14
+ # try mangled names for the version included with JRuby >=1.6.0.RC3
15
+ java.lang.Class.for_name 'org.jruby.org.objectweb.asm.Opcodes'
16
+
17
+ # no error, proceed with mangled name
18
+ asm_package = Java::org.jruby.org.objectweb.asm
19
+ java_import asm_package.Opcodes
20
+ rescue Exception
21
+ # fall back on standard names
22
+ asm_package = org.objectweb.asm
23
+ java_import asm_package.Opcodes
24
+ end
25
+ end
26
+ java_import asm_package.Label
27
+ java_import asm_package.Type
28
+ java_import asm_package.AnnotationVisitor
29
+ java_import asm_package.ClassVisitor
30
+ java_import asm_package.FieldVisitor
31
+ java_import asm_package.MethodVisitor
32
+ java_import asm_package.ClassReader
33
+ java_import asm_package.ClassWriter
34
+ java_import asm_package.util.CheckClassAdapter
35
+ java_import asm_package.signature.SignatureReader
36
+ java_import asm_package.signature.SignatureVisitor
37
+ java_import asm_package.signature.SignatureWriter
38
+
39
+ # MethodHandle was introduced in ASM 4.0, and is only available to
40
+ # JRuby > 1.6.1
41
+ begin
42
+ java_import asm_package.MethodHandle
43
+ rescue
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,624 @@
1
+ require 'bitescript/asm3/bytecode'
2
+ require 'bitescript/asm3/signature'
3
+ require 'fileutils'
4
+
5
+ module BiteScript
6
+ module Util
7
+ def type_from_dotted(dotted_name)
8
+ JavaUtilities.get_proxy_class(dotted_name).java_class
9
+ end
10
+ end
11
+
12
+ module QuickTypes
13
+ def void
14
+ Java::void
15
+ end
16
+
17
+ def boolean
18
+ Java::boolean
19
+ end
20
+
21
+ def byte
22
+ Java::byte
23
+ end
24
+
25
+ def short
26
+ Java::short
27
+ end
28
+
29
+ def char
30
+ Java::char
31
+ end
32
+
33
+ def int
34
+ Java::int
35
+ end
36
+
37
+ def long
38
+ Java::long
39
+ end
40
+
41
+ def float
42
+ Java::float
43
+ end
44
+
45
+ def double
46
+ Java::double
47
+ end
48
+
49
+ def object
50
+ Java::java.lang.Object
51
+ end
52
+
53
+ def string
54
+ Java::java.lang.String
55
+ end
56
+
57
+ def null
58
+ nil
59
+ end
60
+ end
61
+
62
+ module Annotatable
63
+ java_import "java.lang.annotation.Retention"
64
+ def annotate(cls, runtime=nil)
65
+ if runtime.nil?
66
+ retention = find_retention(cls)
67
+ return if retention == 'SOURCE'
68
+ runtime = retention == 'RUNTIME'
69
+ end
70
+
71
+ annotation = visit_annotation(Signature.ci(cls), runtime)
72
+ annotation.extend AnnotationBuilder
73
+
74
+ yield annotation
75
+ annotation.visit_end
76
+ end
77
+
78
+ def find_retention(cls)
79
+ if cls.kind_of?(BiteScript::ASM::ClassMirror)
80
+ retention = cls.getDeclaredAnnotation('java.lang.annotation.Retention')
81
+ elsif cls.kind_of?(BiteScript::ASM::Type)
82
+ mirror = BiteScript::ASM::ClassMirror.for_name(cls.class_name) rescue nil
83
+ return find_retention(mirror) if mirror
84
+ elsif Java::JavaClass === cls
85
+ retention = cls.annotation(Retention.java_class)
86
+ else
87
+ retention = cls.java_class.annotation(Retention.java_class)
88
+ end
89
+ return 'CLASS' if retention.nil?
90
+ return retention.value.name
91
+ end
92
+ end
93
+
94
+ class FileBuilder
95
+ include Util
96
+ include QuickTypes
97
+
98
+ attr_accessor :file_name
99
+ attr_accessor :class_builders
100
+ attr_accessor :imports
101
+ attr_accessor :package
102
+
103
+ def initialize(file_name)
104
+ @file_name = file_name
105
+ @class_builders = {}
106
+ @imports = {}
107
+ @package = []
108
+
109
+ init_imports
110
+ end
111
+
112
+ def init_imports
113
+ # set up a few useful imports
114
+ @imports[:int.to_s] = Java::int.java_class
115
+ @imports[:string.to_s] = Java::java.lang.String.java_class
116
+ @imports[:object.to_s] = Java::java.lang.Object.java_class
117
+ end
118
+
119
+ def self.build(filename, &block)
120
+ fb = new(filename)
121
+ if block_given?
122
+ fb.instance_eval(&block)
123
+ end
124
+ fb
125
+ end
126
+
127
+ def define_class(class_name, opts, &block)
128
+ pkg = opts[:package] || @package.dup || []
129
+
130
+ class_name = pkg.empty? ? class_name : "#{pkg.join('/')}/#{class_name}"
131
+ class_builder = ClassBuilder.new(self, class_name, @file_name, opts)
132
+ @class_builders[class_name] ||= class_builder # TODO Is this really what we want?
133
+
134
+ if block_given?
135
+ if block.arity == 1
136
+ block.call(class_builder)
137
+ else
138
+ class_builder.instance_eval(&block)
139
+ end
140
+ else
141
+ return class_builder
142
+ end
143
+ end
144
+
145
+ def public_class(class_name, superclass = java.lang.Object, *interfaces, &block)
146
+ define_class(class_name, :visibility => :public, :superclass => superclass, :interfaces => interfaces, &block)
147
+ end
148
+
149
+ def public_interface(class_name, *interfaces, &block)
150
+ define_class(class_name, :visibility => :public, :interface => true, :interfaces => interfaces, &block)
151
+ end
152
+
153
+ def protected_class(class_name, superclass = java.lang.Object, *interfaces, &block)
154
+ define_class(class_name, :visibility => :protected, :superclass => superclass, :interfaces => interfaces, &block)
155
+ end
156
+
157
+ def private_class(class_name, superclass = java.lang.Object, *interfaces, &block)
158
+ define_class(class_name, :visibility => :private, :superclass => superclass, :interfaces => interfaces, &block)
159
+ end
160
+
161
+ def default_class(class_name, superclass = java.lang.Object, *interfaces, &block)
162
+ define_class(class_name, :visibility => :default, :superclass => superclass, :interfaces => interfaces, &block)
163
+ end
164
+
165
+ def generate
166
+ @class_builders.each do |class_name, class_builder|
167
+ class_file = "#{class_name.gsub('.', '/')}.class"
168
+
169
+ yield class_file, class_builder
170
+ end
171
+ end
172
+
173
+ def line(line)
174
+ # No tracking of lines at the file level, so we ignore
175
+ end
176
+
177
+ def package(*names)
178
+ return @package unless names.size > 0
179
+
180
+ packages = unpack_packages(*names)
181
+ @package.concat(packages)
182
+ yield
183
+ @package = @package[0..(packages.size - 1)]
184
+ end
185
+
186
+ def package=(name)
187
+ @package = unpack_packages(name)
188
+ end
189
+
190
+ def unpack_packages(*names)
191
+ package = []
192
+ names.each do |name_maybe_dotted|
193
+ name_maybe_dotted.split(/\./).each do |name|
194
+ package.push name
195
+ end
196
+ end
197
+ package
198
+ end
199
+
200
+ def method?
201
+ false
202
+ end
203
+ end
204
+
205
+ class ClassBuilder
206
+ include Util
207
+ include QuickTypes
208
+ include Annotatable
209
+ include ASM
210
+
211
+ java_import java.lang.Object
212
+ java_import java.lang.Void
213
+ include Signature
214
+
215
+ attr_accessor :class_name
216
+ attr_accessor :superclass
217
+ attr_accessor :constructors
218
+ attr_accessor :methods
219
+ attr_accessor :imports
220
+ attr_accessor :fields
221
+ attr_accessor :interfaces
222
+
223
+ def initialize(file_builder, class_name, file_name, opts)
224
+ @parent = file_builder
225
+ @class_name = class_name
226
+ @superclass = opts[:superclass] || Object
227
+ @interfaces = opts[:interfaces] || []
228
+ @interface = opts[:interface]
229
+ flags = Opcodes::ACC_SUPER
230
+ flags |= Opcodes::ACC_ABSTRACT if opts[:abstract]
231
+ if @interface
232
+ flags = Opcodes::ACC_INTERFACE | Opcodes::ACC_ABSTRACT
233
+ end
234
+
235
+ @class_writer = ClassWriter.new(ClassWriter::COMPUTE_FRAMES | ClassWriter::COMPUTE_MAXS)
236
+
237
+ interface_paths = []
238
+ (@interfaces).each {|interface| interface_paths << path(interface)}
239
+
240
+ visibility = case (opts[:visibility] && opts[:visibility].to_sym)
241
+ when nil
242
+ Opcodes::ACC_PUBLIC # NOTE Not specified means public -- must explicitly ask for default
243
+ when :default
244
+ 0
245
+ when :public
246
+ Opcodes::ACC_PUBLIC
247
+ when :private
248
+ Opcodes::ACC_PRIVATE
249
+ when :protected
250
+ Opcodes::ACC_PROTECTED
251
+ else
252
+ raise "Unknown visibility: #{opts[:visibility]}"
253
+ end
254
+
255
+ @class_writer.visit(BiteScript.bytecode_version, visibility | flags, class_name, nil, path(superclass), interface_paths.to_java(:string))
256
+ @class_writer.visit_source(file_name, nil)
257
+
258
+ @constructor = nil
259
+ @constructors = {}
260
+ @methods = {}
261
+
262
+ @imports = {}
263
+
264
+ @fields = {}
265
+ end
266
+
267
+ def start
268
+ end
269
+
270
+ def stop
271
+ # if we haven't seen a constructor, generate a default one
272
+ unless @constructor || @interface
273
+ method = public_constructor([])
274
+ method.start
275
+ method.aload 0
276
+ method.invokespecial @superclass, "<init>", [Void::TYPE]
277
+ method.returnvoid
278
+ method.stop
279
+ end
280
+ end
281
+
282
+ def generate
283
+ bytes = @class_writer.to_byte_array
284
+ if ENV['BS_CHECK_CLASSES']
285
+ BiteScript::ASM::CheckClassAdapter.verify(
286
+ BiteScript::ASM::ClassReader.new(bytes),
287
+ JRuby.runtime.jruby_class_loader,
288
+ false,
289
+ java.io.PrintWriter.new(java.lang.System.out, true))
290
+ end
291
+ String.from_java_bytes(bytes)
292
+ end
293
+
294
+ %w[public private protected].each do |modifier|
295
+ # instance fields
296
+ eval "
297
+ def #{modifier}_field(name, type)
298
+ field(Opcodes::ACC_#{modifier.upcase}, name, type)
299
+ end
300
+ ", binding, __FILE__, __LINE__
301
+ # static fields
302
+ eval "
303
+ def #{modifier}_static_field(name, type)
304
+ field(Opcodes::ACC_STATIC | Opcodes::ACC_#{modifier.upcase}, name, type)
305
+ end
306
+ ", binding, __FILE__, __LINE__
307
+ # instance methods; also defines a "this" local at index 0
308
+ eval "
309
+ def #{modifier}_method(name, exceptions=[], *signature, &block)
310
+ method(Opcodes::ACC_#{modifier.upcase}, name, signature, exceptions, &block)
311
+ end
312
+ ", binding, __FILE__, __LINE__
313
+ # static methods
314
+ eval "
315
+ def #{modifier}_static_method(name, exceptions=[], *signature, &block)
316
+ method(Opcodes::ACC_STATIC | Opcodes::ACC_#{modifier.upcase}, name, signature, exceptions, &block)
317
+ end
318
+ ", binding, __FILE__, __LINE__
319
+ # native methods
320
+ eval "
321
+ def #{modifier}_native_method(name, exceptions=[], *signature)
322
+ method(Opcodes::ACC_NATIVE | Opcodes::ACC_#{modifier.upcase}, name, signature, exceptions)
323
+ end
324
+ ", binding, __FILE__, __LINE__
325
+ # constructors; also defines a "this" local at index 0
326
+ eval "
327
+ def #{modifier}_constructor(exceptions=[], *signature, &block)
328
+ @constructor = method(Opcodes::ACC_#{modifier.upcase}, \"<init>\", [nil, *signature], exceptions, &block)
329
+ end
330
+ ", binding, __FILE__, __LINE__
331
+ end
332
+
333
+ def static_init(&block)
334
+ method(Opcodes::ACC_STATIC, "<clinit>", [void], [], &block)
335
+ end
336
+
337
+ def build_method(name, visibility, static, exceptions, type, *args)
338
+ flags =
339
+ case visibility
340
+ when :public; Opcodes::ACC_PUBLIC
341
+ when :private; Opcodes::ACC_PRIVATE
342
+ when :protected; Opcodes::ACC_PROTECTED
343
+ end
344
+ flags |= Opcodes::ACC_STATIC if static
345
+ method(flags, name, [type, *args], exceptions)
346
+ end
347
+
348
+ def build_constructor(visibility, exceptions, *args)
349
+ flags =
350
+ case visibility
351
+ when :public; Opcodes::ACC_PUBLIC
352
+ when :private; Opcodes::ACC_PRIVATE
353
+ when :protected; Opcodes::ACC_PROTECTED
354
+ end
355
+ @constructor = method(flags, "<init>", [nil, *args], exceptions)
356
+ end
357
+
358
+ def method(flags, name, signature, exceptions, &block)
359
+ flags |= Opcodes::ACC_ABSTRACT if interface?
360
+ mb = MethodBuilder.new(self, flags, name, exceptions, signature)
361
+
362
+ if name == "<init>"
363
+ constructors[signature[1..-1]] = mb
364
+ else
365
+ methods[name] ||= {}
366
+ methods[name][signature[1..-1]] = mb
367
+ end
368
+
369
+ # non-static methods reserve index 0 for 'this'
370
+ mb.local 'this', self if (flags & Opcodes::ACC_STATIC) == 0
371
+
372
+ if block_given? && !interface?
373
+ mb.start
374
+ if block.arity == 1
375
+ block.call(mb)
376
+ else
377
+ mb.instance_eval(&block)
378
+ end
379
+ mb.stop
380
+ end
381
+
382
+ mb
383
+ end
384
+
385
+ def java_method(name, *params)
386
+ if methods[name]
387
+ method = methods[name][params]
388
+ end
389
+
390
+ method or raise NameError.new("failed to find method #{name}#{sig(params)} on #{self}")
391
+ end
392
+
393
+ def main(&b)
394
+ raise "already defined main" if methods[name]
395
+
396
+ public_static_method "main", [], void, string[], &b
397
+ end
398
+
399
+ def constructor(*params)
400
+ constructors[params] or raise NameError.new("failed to find constructor #{sig(params)} on #{self}")
401
+ end
402
+
403
+ def interface?
404
+ # TODO: interface types
405
+ @interface
406
+ end
407
+
408
+ def field(flags, name, type)
409
+ field = @class_writer.visit_field(flags, name, ci(type), nil, nil)
410
+ field.extend Annotatable
411
+ end
412
+
413
+ # name for signature generation using the class being generated
414
+ def name
415
+ @class_name
416
+ end
417
+
418
+ # never generating an array
419
+ def array?
420
+ false
421
+ end
422
+
423
+ # never generating a primitive
424
+ def primitive?
425
+ false
426
+ end
427
+
428
+ def this
429
+ self
430
+ end
431
+
432
+ def visit_annotation(*args)
433
+ @class_writer.visit_annotation(*args)
434
+ end
435
+
436
+ def new_method(modifiers, name, signature, exceptions)
437
+ exceptions ||= []
438
+ unless exceptions.kind_of?(Array)
439
+ raise ArgumentError, "Expected array of exceptions, got #{exceptions.inspect}"
440
+ end
441
+ exceptions = exceptions.map {|e| path(e)}
442
+ @class_writer.visit_method(modifiers, name, sig(*signature), nil, exceptions.to_java(:string))
443
+ end
444
+
445
+ def macro(name, &b)
446
+ MethodBuilder.send :define_method, name, &b
447
+ end
448
+ end
449
+
450
+ class MethodBuilder
451
+ include QuickTypes
452
+ include Annotatable
453
+ include BiteScript::Bytecode
454
+ include ASM
455
+
456
+ attr_reader :method_visitor
457
+ attr_reader :static
458
+ alias :static? :static
459
+ attr_reader :signature
460
+ attr_reader :name
461
+ attr_reader :class_builder
462
+
463
+ def initialize(class_builder, modifiers, name, exceptions, signature)
464
+ @class_builder = class_builder
465
+ @modifiers = modifiers
466
+ @name = name
467
+ @signature = signature
468
+
469
+ @method_visitor = class_builder.new_method(modifiers, name, signature, exceptions)
470
+
471
+ @locals = {}
472
+ @next_local = 0
473
+
474
+ @static = (modifiers & Opcodes::ACC_STATIC) != 0
475
+ @start_label = labels[:_start] = self.label
476
+ @end_label = labels[:_end] = self.label
477
+ @exceptions = exceptions || []
478
+ end
479
+
480
+ def parameter_types
481
+ signature[1..-1]
482
+ end
483
+
484
+ def return_type
485
+ signature[0]
486
+ end
487
+
488
+ def declaring_class
489
+ @class_builder
490
+ end
491
+
492
+ def self.build(class_builder, modifiers, name, signature, &block)
493
+ mb = MethodBuilder.new(class_builder, modifiers, name, signature)
494
+ mb.start
495
+ if block.arity == 1
496
+ block.call(mb)
497
+ else
498
+ mb.instance_eval(&block)
499
+ end
500
+ mb.stop
501
+ end
502
+
503
+ def self.build2(class_builder, modifiers, name, signature, &block)
504
+ mb = MethodBuilder.new(class_builder, modifiers, name, signature)
505
+ mb.start
506
+ block.call(mb)
507
+ mb.stop
508
+ end
509
+
510
+ def generate(&block)
511
+ start
512
+ block.call(self)
513
+ stop
514
+ end
515
+
516
+ def this
517
+ @class_builder
518
+ end
519
+
520
+ def local(name, type=nil)
521
+ if name == "this" && @static
522
+ raise "'this' attempted to load from static method"
523
+ end
524
+
525
+ if @locals[name]
526
+ return @locals[name][-1][0]
527
+ else
528
+ raise ArgumentError, 'Local type required' unless type
529
+ return push_local(name, type, @start_label)
530
+ end
531
+ end
532
+
533
+ def push_local(name, type, start=nil)
534
+ start ||= self.label.set!
535
+ type = ci(type)
536
+ big = "JD".include? type
537
+ match = @locals[name].find {|local| !big || local[1]} if @locals[name]
538
+ if match
539
+ index = match[0]
540
+ else
541
+ index = @next_local
542
+ @next_local += 1
543
+ @next_local += 1 if big
544
+ end
545
+
546
+ if @locals[name] && @locals[name].size > 0
547
+ local_debug_info(name, @locals[name][-1])
548
+ else
549
+ @locals[name] = []
550
+ end
551
+ @locals[name] << [index, big, type, start]
552
+ index
553
+ end
554
+
555
+ def local_debug_info(name, local, end_label=nil)
556
+ return unless local
557
+ index, big, type, start = local
558
+ end_label ||= self.label.set!
559
+ method_visitor.visit_local_variable(name, type, nil,
560
+ start.label,
561
+ end_label.label,
562
+ index)
563
+ end
564
+
565
+ def pop_local(name)
566
+ here = self.label.set!
567
+ local_debug_info(name, @locals[name].pop, here)
568
+ @locals[name][-1][-1] = here if @locals[name].size > 0
569
+ end
570
+
571
+ def visit_annotation(*args)
572
+ @method_visitor.visit_annotation(*args)
573
+ end
574
+ end
575
+
576
+ module AnnotationBuilder
577
+ include Signature
578
+ def method_missing(name, val)
579
+ name_str = name.to_s
580
+ if name_str[-1] == ?=
581
+ name_str = name_str[0..-2]
582
+ if Array === val
583
+ array(name_str) do |ary|
584
+ val.each {|x| ary.visit(nil, x)}
585
+ end
586
+ else
587
+ visit name_str, val
588
+ end
589
+ else
590
+ super
591
+ end
592
+ end
593
+ def value(k, v)
594
+ visit k, v
595
+ end
596
+ def annotation(name, cls)
597
+ if Java::JavaClass === cls || BiteScript::ASM::Type === cls
598
+ java_class = cls
599
+ else
600
+ java_class = cls.java_class
601
+ end
602
+
603
+ sub_annotation = visit_annotation(name, ci(java_class))
604
+ sub_annotation.extend AnnotationBuilder
605
+ yield sub_annotation
606
+ sub_annotation.visit_end
607
+ end
608
+ def array(name)
609
+ sub_annotation = visit_array(name)
610
+ sub_annotation.extend AnnotationBuilder
611
+ yield sub_annotation
612
+ sub_annotation.visit_end
613
+ end
614
+ def enum(name, cls, value)
615
+ if JavaClass == cls
616
+ java_class = cls
617
+ else
618
+ java_class = cls.java_class
619
+ end
620
+
621
+ visit_enum(name, ci(java_class), value)
622
+ end
623
+ end
624
+ end