Class: Mirah::AST::Block

Inherits:
Node
  • Object
show all
Includes:
Java::DubyLangCompiler::Block, Scope, Scoped
Defined in:
lib/mirah/ast/structure.rb

Instance Attribute Summary

Attributes included from Scope

#static_scope, #type_scope

Attributes inherited from Node

#children, #inferred_type, #newline, #parent, #position

Instance Method Summary collapse

Methods included from Scoped

#containing_scope, #scope

Methods inherited from Node

#<<, ===, #[], #[]=, #_dump, _load, #_set_parent, child, child_name, #child_nodes, #each, #empty?, #expr?, #inferred_type!, #initialize_copy, #insert, #inspect, #inspect_children, #line_number, #log, #precompile, #resolve_if, #resolved!, #resolved?, #simple_name, #string_value, #temp, #to_s, #top_level?, #validate_child, #validate_children

Constructor Details

#initialize(parent, position, &block) ⇒ Block

Returns a new instance of Block.



137
138
139
140
141
142
# File 'lib/mirah/ast/structure.rb', line 137

def initialize(parent, position, &block)
  super(parent, position) do
    static_scope.parent = scope.static_scope
    yield(self) if block_given?
  end
end

Instance Method Details

#add_methods(klass, binding, typer) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/mirah/ast/structure.rb', line 177

def add_methods(klass, binding, typer)
  method_definitions = body.select{ |node| node.kind_of? MethodDefinition }
  
  if method_definitions.empty?
    build_method(klass, binding, typer)
  else
    # TODO warn if there are non method definition nodes
    # they won't be used at all currently--so it'd be nice to note that.
    method_definitions.each do |node|
      node.static_scope = static_scope
      node.binding_type = binding
      klass.append_node(node)
    end
  end
end

#build_method(klass, binding, typer) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/mirah/ast/structure.rb', line 193

def build_method(klass, binding, typer)
  # find all methods which would not otherwise be on java.lang.Object
  impl_methods = find_methods(klass.interfaces).select do |m|
    begin
      # Very cumbersome. Not sure how it got this way.
      mirror = BiteScript::ASM::ClassMirror.for_name('java.lang.Object')
      mtype = Mirah::JVM::Types::Type.new(mirror)
      mtype.java_method m.name, *m.argument_types
    rescue NameError
      # not found on Object
      next true
    end
    # found on Object
    next false
  end

  raise "Multiple abstract methods found within given interface [#{impl_methods.map(&:name).join(', ')}]; cannot use block" if impl_methods.size > 1
  impl_methods.each do |method|
    mdef = klass.define_method(position,
                        method.name,
                        method.return_type,
                        args.dup) do |mdef|
      mdef.static_scope = static_scope
      mdef.binding_type = binding
      mdef.body = body.dup
    end
    typer.infer(mdef.body, method.return_type != typer.no_type)
  end
end

#find_methods(interfaces) ⇒ Object



223
224
225
226
227
228
229
230
231
232
# File 'lib/mirah/ast/structure.rb', line 223

def find_methods(interfaces)
  methods = []
  interfaces = interfaces.dup
  until interfaces.empty?
    interface = interfaces.pop
    methods += interface.declared_instance_methods.select {|m| m.abstract?}
    interfaces.concat(interface.interfaces)
  end
  methods
end

#prepare(typer, method) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/mirah/ast/structure.rb', line 144

def prepare(typer, method)
  mirah = typer.transformer
  interface = method.argument_types[-1]
  outer_class = scope.defining_class
  
  binding = scope.binding_type(mirah)
  
  name = "#{outer_class.name}$#{mirah.tmp}"

  klass = mirah.define_closure(position, name, outer_class)
  klass.interfaces = [interface]
  klass.define_constructor(position,
                           ['binding', binding]) do |c|
      mirah.eval("@binding = binding", '-', c, 'binding')
  end

  # TODO We need a special scope here that allows access to the
  # outer class.
  static_scope.self_type = typer.infer(klass, true)

  add_methods(klass, binding, typer)

  call = parent
  instance = Call.new(call, position, 'new')
  instance.target = Constant.new(call, position, name)
  instance.parameters = [
    BindingReference.new(instance, position, binding)
  ]
  call.parameters << instance
  call.block = nil
  typer.infer(instance, true)
end