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.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/bitescript/builder.rb', line 223

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 = ClassWriter.new(ClassWriter::COMPUTE_FRAMES | ClassWriter::COMPUTE_MAXS)
  
  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.



215
216
217
# File 'lib/bitescript/builder.rb', line 215

def class_name
  @class_name
end

#constructorsObject

Returns the value of attribute constructors.



217
218
219
# File 'lib/bitescript/builder.rb', line 217

def constructors
  @constructors
end

#fieldsObject

Returns the value of attribute fields.



220
221
222
# File 'lib/bitescript/builder.rb', line 220

def fields
  @fields
end

#importsObject

Returns the value of attribute imports.



219
220
221
# File 'lib/bitescript/builder.rb', line 219

def imports
  @imports
end

#interfacesObject

Returns the value of attribute interfaces.



221
222
223
# File 'lib/bitescript/builder.rb', line 221

def interfaces
  @interfaces
end

#methodsObject

Returns the value of attribute methods.



218
219
220
# File 'lib/bitescript/builder.rb', line 218

def methods
  @methods
end

#superclassObject

Returns the value of attribute superclass.



216
217
218
# File 'lib/bitescript/builder.rb', line 216

def superclass
  @superclass
end

Instance Method Details

#array?Boolean

never generating an array

Returns:

  • (Boolean)


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

def array?
  false
end

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



358
359
360
361
362
363
364
365
366
# File 'lib/bitescript/builder.rb', line 358

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



347
348
349
350
351
352
353
354
355
356
# File 'lib/bitescript/builder.rb', line 347

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



409
410
411
# File 'lib/bitescript/builder.rb', line 409

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

#field(flags, name, type) ⇒ Object



418
419
420
421
# File 'lib/bitescript/builder.rb', line 418

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

#generateObject



282
283
284
285
286
287
288
289
290
291
292
# File 'lib/bitescript/builder.rb', line 282

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)


413
414
415
416
# File 'lib/bitescript/builder.rb', line 413

def interface?
  # TODO: interface types
  @interface
end

#java_method(name, *params) ⇒ Object



395
396
397
398
399
400
401
# File 'lib/bitescript/builder.rb', line 395

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



455
456
457
# File 'lib/bitescript/builder.rb', line 455

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

#main(&b) ⇒ Object



403
404
405
406
407
# File 'lib/bitescript/builder.rb', line 403

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



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/bitescript/builder.rb', line 368

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



424
425
426
# File 'lib/bitescript/builder.rb', line 424

def name
  @class_name
end

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



446
447
448
449
450
451
452
453
# File 'lib/bitescript/builder.rb', line 446

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)


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

def primitive?
  false
end

#startObject



267
268
# File 'lib/bitescript/builder.rb', line 267

def start
end

#static_init(&block) ⇒ Object



343
344
345
# File 'lib/bitescript/builder.rb', line 343

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

#stopObject



270
271
272
273
274
275
276
277
278
279
280
# File 'lib/bitescript/builder.rb', line 270

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



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

def this
  self
end

#visit_annotation(*args) ⇒ Object



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

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