Class: BiteScript::ClassBuilder

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Signature

ci, class_id, classname, path, sig, signature

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.



220
221
222
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 220

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
  if @interface
    flags = Opcodes::ACC_INTERFACE | Opcodes::ACC_ABSTRACT
  end

  @class_writer = ClassWriter.new(ClassWriter::COMPUTE_MAXS)
  if ENV['BS_CHECK_CLASSES']
    @real_class_writer = @class_writer
    @class_writer = CheckClassAdapter.new(@class_writer)
  end
  
  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.



212
213
214
# File 'lib/bitescript/builder.rb', line 212

def class_name
  @class_name
end

#constructorsObject

Returns the value of attribute constructors.



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

def constructors
  @constructors
end

#fieldsObject

Returns the value of attribute fields.



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

def fields
  @fields
end

#importsObject

Returns the value of attribute imports.



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

def imports
  @imports
end

#interfacesObject

Returns the value of attribute interfaces.



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

def interfaces
  @interfaces
end

#methodsObject

Returns the value of attribute methods.



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

def methods
  @methods
end

#superclassObject

Returns the value of attribute superclass.



213
214
215
# File 'lib/bitescript/builder.rb', line 213

def superclass
  @superclass
end

Instance Method Details

#array?Boolean

never generating an array

Returns:

  • (Boolean)


395
396
397
# File 'lib/bitescript/builder.rb', line 395

def array?
  false
end

#constructor(*params) ⇒ Object



375
376
377
# File 'lib/bitescript/builder.rb', line 375

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

#field(flags, name, type) ⇒ Object



384
385
386
387
# File 'lib/bitescript/builder.rb', line 384

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
# File 'lib/bitescript/builder.rb', line 282

def generate
  if ENV['BS_CHECK_CLASSES']
    class_writer = @real_class_writer
  else
    class_writer = @class_writer
  end
  String.from_java_bytes(class_writer.to_byte_array)
end

#interface?Boolean

Returns:

  • (Boolean)


379
380
381
382
# File 'lib/bitescript/builder.rb', line 379

def interface?
  # TODO: interface types
  @interface
end

#java_method(name, *params) ⇒ Object



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

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



421
422
423
# File 'lib/bitescript/builder.rb', line 421

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

#main(&b) ⇒ Object



369
370
371
372
373
# File 'lib/bitescript/builder.rb', line 369

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



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/bitescript/builder.rb', line 334

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



390
391
392
# File 'lib/bitescript/builder.rb', line 390

def name
  @class_name
end

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



412
413
414
415
416
417
418
419
# File 'lib/bitescript/builder.rb', line 412

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)


400
401
402
# File 'lib/bitescript/builder.rb', line 400

def primitive?
  false
end

#startObject



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

def start
end

#static_init(&block) ⇒ Object



330
331
332
# File 'lib/bitescript/builder.rb', line 330

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



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

def this
  self
end

#visit_annotation(*args) ⇒ Object



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

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