bitescript 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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