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.



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
290
291
292
293
294
# File 'lib/bitescript/builder.rb', line 248

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.



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

def class_name
  @class_name
end

#constructorsObject

Returns the value of attribute constructors.



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

def constructors
  @constructors
end

#fieldsObject

Returns the value of attribute fields.



245
246
247
# File 'lib/bitescript/builder.rb', line 245

def fields
  @fields
end

#importsObject

Returns the value of attribute imports.



244
245
246
# File 'lib/bitescript/builder.rb', line 244

def imports
  @imports
end

#interfacesObject

Returns the value of attribute interfaces.



246
247
248
# File 'lib/bitescript/builder.rb', line 246

def interfaces
  @interfaces
end

#methodsObject

Returns the value of attribute methods.



243
244
245
# File 'lib/bitescript/builder.rb', line 243

def methods
  @methods
end

#superclassObject

Returns the value of attribute superclass.



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

def superclass
  @superclass
end

Instance Method Details

#array?Boolean

never generating an array

Returns:

  • (Boolean)


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

def array?
  false
end

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



387
388
389
390
391
392
393
394
395
# File 'lib/bitescript/builder.rb', line 387

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



376
377
378
379
380
381
382
383
384
385
# File 'lib/bitescript/builder.rb', line 376

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



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

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

#field(flags, name, type) ⇒ Object



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

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

#generateObject



311
312
313
314
315
316
317
318
319
320
321
# File 'lib/bitescript/builder.rb', line 311

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)


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

def interface?
  # TODO: interface types
  @interface
end

#java_method(name, *params) ⇒ Object



424
425
426
427
428
429
430
# File 'lib/bitescript/builder.rb', line 424

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



484
485
486
# File 'lib/bitescript/builder.rb', line 484

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

#main(&b) ⇒ Object



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

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



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/bitescript/builder.rb', line 397

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



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

def name
  @class_name
end

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



475
476
477
478
479
480
481
482
# File 'lib/bitescript/builder.rb', line 475

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)


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

def primitive?
  false
end

#startObject



296
297
# File 'lib/bitescript/builder.rb', line 296

def start
end

#static_init(&block) ⇒ Object



372
373
374
# File 'lib/bitescript/builder.rb', line 372

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

#stopObject



299
300
301
302
303
304
305
306
307
308
309
# File 'lib/bitescript/builder.rb', line 299

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



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

def this
  self
end

#visit_annotation(*args) ⇒ Object



471
472
473
# File 'lib/bitescript/builder.rb', line 471

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