Class: BiteScript::ClassBuilder

Inherits:
Object
  • Object
show all
Includes:
ASM, Annotatable, QuickTypes, Signature, Util
Defined in:
lib/bitescript/builder.rb,
lib/bitescript/asm3/builder.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Signature

ci, class_id, classname, path, sig, signature, tipath, type_insn_path

Methods included from Annotatable

#annotate, #find_retention

Methods included from QuickTypes

#boolean, #byte, #char, #double, #float, #int, #long, #null, #object, #short, #string, #void

Methods included from Util

#type_from_dotted

Constructor Details

#initialize(file_builder, class_name, file_name, opts) ⇒ ClassBuilder

Returns a new instance of ClassBuilder.



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/bitescript/builder.rb', line 243

def initialize(file_builder, class_name, file_name, opts) 
  @parent = file_builder
  @class_name = class_name
  @superclass = opts[:superclass] || Object
  @interfaces = opts[:interfaces] || []
  @interface = opts[:interface]
  flags = Opcodes::ACC_SUPER
  flags |= Opcodes::ACC_ABSTRACT if opts[:abstract]
  if @interface
    flags = Opcodes::ACC_INTERFACE | Opcodes::ACC_ABSTRACT
  end

  @class_writer = CustomClassWriter.new(
      0 |
      (BiteScript.compute_frames ? ClassWriter::COMPUTE_FRAMES : 0) |
      (BiteScript.compute_maxs ? ClassWriter::COMPUTE_MAXS : 0),
      &opts[:widen])
  
  interface_paths = []
  (@interfaces).each {|interface| interface_paths << path(interface)}

  visibility = case (opts[:visibility] && opts[:visibility].to_sym)
    when nil
      Opcodes::ACC_PUBLIC  # NOTE Not specified means public -- must explicitly ask for default
    when :default
      0
    when :public
      Opcodes::ACC_PUBLIC
    when :private
      Opcodes::ACC_PRIVATE
    when :protected
      Opcodes::ACC_PROTECTED
    else
      raise "Unknown visibility: #{opts[:visibility]}"
  end

  @class_writer.visit(BiteScript.bytecode_version, visibility | flags, class_name, nil, path(superclass), interface_paths.to_java(:string))
  @class_writer.visit_source(file_name, nil)

  @constructor = nil
  @constructors = {}
  @methods = {}
  
  @imports = {}
  
  @fields = {}
end

Instance Attribute Details

#class_nameObject

Returns the value of attribute class_name.



235
236
237
# File 'lib/bitescript/builder.rb', line 235

def class_name
  @class_name
end

#constructorsObject

Returns the value of attribute constructors.



237
238
239
# File 'lib/bitescript/builder.rb', line 237

def constructors
  @constructors
end

#fieldsObject

Returns the value of attribute fields.



240
241
242
# File 'lib/bitescript/builder.rb', line 240

def fields
  @fields
end

#importsObject

Returns the value of attribute imports.



239
240
241
# File 'lib/bitescript/builder.rb', line 239

def imports
  @imports
end

#interfacesObject

Returns the value of attribute interfaces.



241
242
243
# File 'lib/bitescript/builder.rb', line 241

def interfaces
  @interfaces
end

#methodsObject

Returns the value of attribute methods.



238
239
240
# File 'lib/bitescript/builder.rb', line 238

def methods
  @methods
end

#superclassObject

Returns the value of attribute superclass.



236
237
238
# File 'lib/bitescript/builder.rb', line 236

def superclass
  @superclass
end

Instance Method Details

#array?Boolean

never generating an array

Returns:

  • (Boolean)


453
454
455
# File 'lib/bitescript/builder.rb', line 453

def array?
  false
end

#build_constructor(visibility, exceptions, *args) ⇒ Object



382
383
384
385
386
387
388
389
390
# File 'lib/bitescript/builder.rb', line 382

def build_constructor(visibility, exceptions, *args)
  flags =
    case visibility
    when :public; Opcodes::ACC_PUBLIC
    when :private; Opcodes::ACC_PRIVATE
    when :protected; Opcodes::ACC_PROTECTED
    end
  @constructor = method(flags, "<init>", [nil, *args], exceptions)
end

#build_method(name, visibility, static, exceptions, type, *args) ⇒ Object



371
372
373
374
375
376
377
378
379
380
# File 'lib/bitescript/builder.rb', line 371

def build_method(name, visibility, static, exceptions, type, *args)
  flags =
    case visibility
    when :public; Opcodes::ACC_PUBLIC
    when :private; Opcodes::ACC_PRIVATE
    when :protected; Opcodes::ACC_PROTECTED
    end
  flags |= Opcodes::ACC_STATIC if static
  method(flags, name, [type, *args], exceptions)
end

#constructor(*params) ⇒ Object



433
434
435
# File 'lib/bitescript/builder.rb', line 433

def constructor(*params)
  constructors[params] or raise NameError.new("failed to find constructor #{sig(params)} on #{self}")
end

#field(flags, name, type) ⇒ Object



442
443
444
445
# File 'lib/bitescript/builder.rb', line 442

def field(flags, name, type)
  field = @class_writer.visit_field(flags, name, ci(type), nil, nil)
  field.extend Annotatable
end

#generateObject



306
307
308
309
310
311
312
313
314
315
316
# File 'lib/bitescript/builder.rb', line 306

def generate
  bytes = @class_writer.to_byte_array
  if ENV['BS_CHECK_CLASSES']
    BiteScript::ASM::CheckClassAdapter.verify(
        BiteScript::ASM::ClassReader.new(bytes),
        JRuby.runtime.jruby_class_loader,
        false,
        java.io.PrintWriter.new(java.lang.System.out, true))
  end
  String.from_java_bytes(bytes)
end

#interface?Boolean

Returns:

  • (Boolean)


437
438
439
440
# File 'lib/bitescript/builder.rb', line 437

def interface?
  # TODO: interface types
  @interface
end

#java_method(name, *params) ⇒ Object



419
420
421
422
423
424
425
# File 'lib/bitescript/builder.rb', line 419

def java_method(name, *params)
  if methods[name]
    method = methods[name][params]
  end

  method or raise NameError.new("failed to find method #{name}#{sig(params)} on #{self}")
end

#macro(name, &b) ⇒ Object



479
480
481
# File 'lib/bitescript/builder.rb', line 479

def macro(name, &b)
  MethodBuilder.send :define_method, name, &b
end

#main(&b) ⇒ Object



427
428
429
430
431
# File 'lib/bitescript/builder.rb', line 427

def main(&b)
  raise "already defined main" if methods[name]

  public_static_method "main", [], void, string[], &b
end

#method(flags, name, signature, exceptions, &block) ⇒ Object



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/bitescript/builder.rb', line 392

def method(flags, name, signature, exceptions, &block)
  flags |= Opcodes::ACC_ABSTRACT if interface?
  mb = MethodBuilder.new(self, flags, name, exceptions, signature)

  if name == "<init>"
    constructors[signature[1..-1]] = mb
  else
    methods[name] ||= {}
    methods[name][signature[1..-1]] = mb
  end

  # non-static methods reserve index 0 for 'this'
  mb.local 'this', self if (flags & Opcodes::ACC_STATIC) == 0
  
  if block_given? && !interface?
    mb.start
    if block.arity == 1
      block.call(mb)
    else
      mb.instance_eval(&block)
    end
    mb.stop
  end

  mb
end

#nameObject

name for signature generation using the class being generated



448
449
450
# File 'lib/bitescript/builder.rb', line 448

def name
  @class_name
end

#new_method(modifiers, name, signature, exceptions) ⇒ Object



470
471
472
473
474
475
476
477
# File 'lib/bitescript/builder.rb', line 470

def new_method(modifiers, name, signature, exceptions)
  exceptions ||= []
  unless exceptions.kind_of?(Array)
    raise ArgumentError, "Expected array of exceptions, got #{exceptions.inspect}"
  end
  exceptions = exceptions.map {|e| path(e)}
  @class_writer.visit_method(modifiers, name, sig(*signature), nil, exceptions.to_java(:string))
end

#primitive?Boolean

never generating a primitive

Returns:

  • (Boolean)


458
459
460
# File 'lib/bitescript/builder.rb', line 458

def primitive?
  false
end

#startObject



291
292
# File 'lib/bitescript/builder.rb', line 291

def start
end

#static_init(&block) ⇒ Object



367
368
369
# File 'lib/bitescript/builder.rb', line 367

def static_init(&block)
  method(Opcodes::ACC_STATIC, "<clinit>", [void], [], &block)
end

#stopObject



294
295
296
297
298
299
300
301
302
303
304
# File 'lib/bitescript/builder.rb', line 294

def stop
  # if we haven't seen a constructor, generate a default one
  unless @constructor || @interface
    method = public_constructor([])
    method.start
    method.aload 0
    method.invokespecial @superclass, "<init>", [Void::TYPE]
    method.returnvoid
    method.stop
  end
end

#thisObject



462
463
464
# File 'lib/bitescript/builder.rb', line 462

def this
  self
end

#visit_annotation(*args) ⇒ Object



466
467
468
# File 'lib/bitescript/builder.rb', line 466

def visit_annotation(*args)
  @class_writer.visit_annotation(*args)
end