rubyx/lib/slot_machine/method_compiler.rb

91 lines
3.0 KiB
Ruby
Raw Normal View History

2019-10-03 20:07:55 +02:00
module SlotMachine
2019-10-03 20:07:55 +02:00
# MethodCompiler is used to generate SlotMachine instructions for methods
# and to instantiate the methods correctly.
class MethodCompiler < CallableCompiler
2020-02-26 18:01:01 +01:00
# helper method for builtin mainly
# the class_name is a symbol, which is resolved to the instance_type of that class
#
# return compiler_for_type with the resolved type
#
def self.compiler_for_class( class_name , method_name , args , frame )
raise "create_method #{class_name}.#{class_name.class}" unless class_name.is_a? Symbol
clazz = Parfait.object_space.get_class_by_name! class_name
compiler_for_type( clazz.instance_type , method_name , args , frame)
end
# create a method for the given type ( Parfait type object)
# method_name is a Symbol
# args a hash that will be converted to a type
# the created method is set as the current and the given type too
# return the compiler
def self.compiler_for_type( type , method_name , args , frame)
raise "create_method #{type.inspect} is not a Type" unless type.is_a? Parfait::Type
raise "Args must be Type #{args}" unless args.is_a?(Parfait::Type)
raise "create_method #{method_name}.#{method_name.class}" unless method_name.is_a? Symbol
method = type.create_method( method_name , args , frame)
self.new(method)
end
def initialize( method )
super(method)
end
def source_name
"#{@callable.self_type.name}.#{@callable.name}"
end
def get_method
@callable
end
# sometimes the method is used as source (tb reviewed)
def source
@callable
end
# drop down to risc by converting this compilers instructions to risc.
# and the doing the same for any block_compilers
2019-08-10 11:42:47 +02:00
def to_risc
2019-10-03 20:07:55 +02:00
risc_compiler = Risc::MethodCompiler.new(@callable , slot_instructions)
instructions_to_risc(risc_compiler)
risc_compiler
2019-08-10 11:42:47 +02:00
end
2020-02-26 18:01:01 +01:00
# create a block in the scope of the method.
# Blocks are like other constants, exept with code.
# They need to be compiled, so a list of them is kept
def create_block(arg_type , frame_type)
@callable.create_block(arg_type ,frame_type)
end
# determine how given name need to be accsessed.
# For methods the options are args or frame
def slot_type_for(name)
2019-08-22 21:56:44 +02:00
if index = @callable.arguments_type.variable_index(name)
return ["arg#{index}".to_sym]
end
index = @callable.frame_type.variable_index(name)
raise "no such local or argument #{name} for #{callable.name}:#{callable.frame_type.hash}" unless index
return ["local#{index}".to_sym]
end
# return true or false if the given name is in scope (arg/local)
def in_scope?(name)
ret = true if @callable.arguments_type.variable_index(name)
ret = @callable.frame_type.variable_index(name) unless ret
ret
end
# Only for init, as init has no return
# kind of private
def _reset_for_init
2019-10-03 20:07:55 +02:00
@slot_instructions = Label.new(source_name, source_name)
@current = @slot_instructions
end
end
end