diff --git a/lib/mom/callable_compiler.rb b/lib/mom/callable_compiler.rb index 3aff0fcb..88848412 100644 --- a/lib/mom/callable_compiler.rb +++ b/lib/mom/callable_compiler.rb @@ -34,6 +34,12 @@ module Mom @constants << const end + # translate to Risc, ie a Risc level CallableCompiler + # abstract functon that needs to be implemented by Method/BlockCompiler + def to_risc + raise "abstract in #{self.class}" + end + # add a risc instruction after the current (insertion point) # the added instruction will become the new insertion point def add_code( instruction ) diff --git a/lib/mom/mom_collection.rb b/lib/mom/mom_collection.rb index 06948d1e..f574b4f7 100644 --- a/lib/mom/mom_collection.rb +++ b/lib/mom/mom_collection.rb @@ -37,49 +37,26 @@ module Mom self end - # Translate code to whatever cpu is specified. - # Currently only :arm and :interpret - # - # Translating means translating the initial jump - # and then translating all methods - def translate( platform_sym ) - platform_sym = platform_sym.to_s.capitalize - platform = Risc::Platform.for(platform_sym) - assemblers = translate_methods( platform.translator ) - Risc::Linker.new(platform , assemblers , constants) + def to_risc( ) + riscs = [] + # to_risc all compilers + # for each suffling constnts and fist label, then all instructions (see below) + # then create risc collection + Risc::RiscCollection.new(riscs) end - # go through all methods and translate them to cpu, given the translator - def translate_methods(translator) - compilers.collect do |compiler| - #log.debug "Translate method #{compiler.method.name}" - translate_method(compiler , translator) - end.flatten - end - - # translate one method, which means the method itself and all blocks inside it - # returns an array of assemblers - def translate_method( method_compiler , translator) - all = [] - all << translate_cpu( method_compiler , translator ) - method_compiler.block_compilers.each do |block_compiler| - all << translate_cpu(block_compiler , translator) + # convert the given mom instruction to_risc and then add it (see add_code) + # continue down the instruction chain unti depleted + # (adding moves the insertion point so the whole mom chain is added as a risc chain) + def add_mom( instruction ) + while( instruction ) + raise "whats this a #{instruction}" unless instruction.is_a?(Mom::Instruction) + #puts "adding mom #{instruction.to_s}:#{instruction.next.to_s}" + instruction.to_risc( self ) + reset_regs + #puts "adding risc #{risc.to_s}:#{risc.next.to_s}" + instruction = instruction.next end - all - end - - # compile the callable (method or block) to cpu - # return an Assembler that will then translate to binary - def translate_cpu(compiler , translator) - risc = compiler.risc_instructions - cpu_instructions = risc.to_cpu(translator) - nekst = risc.next - while(nekst) - cpu = nekst.to_cpu(translator) # returning nil means no replace - cpu_instructions << cpu if cpu - nekst = nekst.next - end - Risc::Assembler.new(compiler.callable , cpu_instructions ) end end diff --git a/lib/risc.rb b/lib/risc.rb index 3be971ef..e987d5c6 100644 --- a/lib/risc.rb +++ b/lib/risc.rb @@ -35,6 +35,7 @@ require_relative "risc/callable_compiler" require_relative "risc/method_compiler" require_relative "risc/block_compiler" require_relative "risc/assembler" +require_relative "risc/risc_collection" class Integer def fits_u8? diff --git a/lib/risc/callable_compiler.rb b/lib/risc/callable_compiler.rb index 8a138d06..dacb24b2 100644 --- a/lib/risc/callable_compiler.rb +++ b/lib/risc/callable_compiler.rb @@ -4,23 +4,21 @@ module Risc # class shared by BlockCompiler and MethodCompiler # - risc_instructions: The sequence of risc level instructions that mom was compiled to - # - cpu_instructions: The sequence of cpu specific instructions that the - # risc_instructions was compiled to # Instructions derive from class Instruction and form a linked list - + # - constants is an array of Parfait objects that need to be available + # - callable is a Method of Block + # - current instruction is where addidion happens + # class CallableCompiler - def initialize( callable ) + # Must pass the callable (method/block) and the constants that were parsed + # Also start instuction, usually a label is mandatory + def initialize( callable , constants , start) @callable = callable @regs = [] - @constants = [] + @constants = constants @block_compilers = [] - @risc_instructions = Risc.label(source_name, source_name) - @current = start = @risc_instructions - add_code Risc.label( source_name, "return_label") - Mom::ReturnSequence.new.to_risc(self) - add_code Risc.label( source_name, "unreachable") - @current = start + @current = @risc_instructions = start reset_regs end attr_reader :risc_instructions , :constants , :block_compilers , :callable , :current @@ -32,19 +30,6 @@ module Risc end end - # convert the given mom instruction to_risc and then add it (see add_code) - # continue down the instruction chain unti depleted - # (adding moves the insertion point so the whole mom chain is added as a risc chain) - def add_mom( instruction ) - while( instruction ) - raise "whats this a #{instruction}" unless instruction.is_a?(Mom::Instruction) - #puts "adding mom #{instruction.to_s}:#{instruction.next.to_s}" - instruction.to_risc( self ) - reset_regs - #puts "adding risc #{risc.to_s}:#{risc.next.to_s}" - instruction = instruction.next - end - end # add a constant (which get created during compilation and need to be linked) def add_constant(const) diff --git a/lib/mom/mom_compiler.rb b/lib/risc/risc_collection.rb similarity index 81% rename from lib/mom/mom_compiler.rb rename to lib/risc/risc_collection.rb index 8f4020f3..bebf1cce 100644 --- a/lib/mom/mom_compiler.rb +++ b/lib/risc/risc_collection.rb @@ -1,16 +1,8 @@ -module Mom - # The Compiler for the Mom level is a collection of Risc level Method compilers, +module Risc + # The Collection for the Risc level is a collection of Risc level Method compilers, # plus functions to translate from the risc to cpu specific code. # - # Builtin functions are created here, lazily, when translate is called. - # Instantiating builtin functions results in a MethodCompiler for that function, and - # to avoid confusion, these should be instantiated only once. - # - # As RubyCompiler pools source at the vool level, when several classes are compiled - # from vool to mom, several MomCompilers get instantiated. They must be merged before - # proceeding with translate. Thus we have a append method. - # - class MomCompiler + class RiscCollection attr_reader :method_compilers # Initialize with an array of risc MethodCompilers diff --git a/lib/rubyx/rubyx_compiler.rb b/lib/rubyx/rubyx_compiler.rb index 2dd83cde..d0a93128 100644 --- a/lib/rubyx/rubyx_compiler.rb +++ b/lib/rubyx/rubyx_compiler.rb @@ -63,7 +63,7 @@ module RubyX # to generate binaries def to_risc(platform) mom = to_mom - mom.translate(platform) + mom.to_risc(platform) end # ruby_to_mom does exactly that, it transform the incoming ruby source (string) diff --git a/lib/vool/class_statement.rb b/lib/vool/class_statement.rb index 254c2fdc..5657fd5e 100644 --- a/lib/vool/class_statement.rb +++ b/lib/vool/class_statement.rb @@ -1,4 +1,13 @@ module Vool + # This represents a class at the vool level. Vool is a syntax tree, + # so here the only child (or children) is a body. + # Body may either be a MethodStatement, or Statements (either empty or + # containing MethodStatement) + # + # We store the class name and the parfait class + # + # The Parfait class gets created lazily on the way down to mom, ie the clazz + # attribute will only be set after to_mom, or a direct call to create_class class ClassStatement < Statement attr_reader :name, :super_class_name , :body attr_reader :clazz @@ -17,6 +26,10 @@ module Vool end end + # This create the Parfait class, and then transforms every method + # + # As there is no class equivalnet in code, a MomCollection is returned, + # which is just a list of Mom::MethodCompilers def to_mom( _ ) create_class_object method_compilers = body.statements.collect do |node| @@ -37,6 +50,10 @@ module Vool @body.each(&block) if @body end + # This creates the Parfait class. But doesn not hadle reopening yet, so only new classes + # Creating the class involves creating the instance_type (or an initial version) + # which means knowing all used names. So we go through the code looking for + # InstanceVariables or InstanceVariable Assignments, to do that. def create_class_object @clazz = Parfait.object_space.get_class_by_name(@name ) if(@clazz) @@ -53,6 +70,7 @@ module Vool ivar_hash[node.name] = :Object end @clazz.set_instance_type( Parfait::Type.for_hash( @clazz , ivar_hash ) ) + @clazz end end diff --git a/lib/vool/method_statement.rb b/lib/vool/method_statement.rb index 2256a9aa..b5ae2bf2 100644 --- a/lib/vool/method_statement.rb +++ b/lib/vool/method_statement.rb @@ -9,7 +9,7 @@ module Vool def to_mom(clazz) raise( "no class in #{self}") unless clazz - method = clazz.add_method_for(name , make_arg_type , make_frame , body ) + method = make_method(clazz) compiler = method.compiler_for(clazz.instance_type) each do |node| ## TODO: must account for nested blocks (someday) next unless node.is_a?(BlockStatement) @@ -18,6 +18,15 @@ module Vool compiler end + # Class to be passed in is a Parfait class + # return VoolMethod + # + # extracted call to create the VoolMethod as this is the place + # where we have all the info. Used in testing. + def make_method(clazz) + clazz.add_method_for(name , make_arg_type , make_frame , body ) + end + def each(&block) block.call(self) @body.each(&block) diff --git a/test/risc/test_callable_compiler.rb b/test/risc/test_callable_compiler.rb new file mode 100644 index 00000000..ea97349d --- /dev/null +++ b/test/risc/test_callable_compiler.rb @@ -0,0 +1,37 @@ +require_relative "helper" +module Risc + class FakeCallable + end + class FakeCallableCompiler < CallableCompiler + def initialize(a,b,c) + super(a,b,c) + end + def source_name + "luke" + end + end + class TestCallableCompiler < MiniTest::Test + + def setup + Parfait.boot!({}) + label = Risc.label("hi","ho") + @compiler = FakeCallableCompiler.new(FakeCallable.new , [] , label) + end + def test_ok + assert @compiler + end + def test_current + assert @compiler.current + end + def test_current_label + assert_equal Label , @compiler.current.class + assert_equal "ho" , @compiler.current.name + end + def test_mom + assert @compiler.risc_instructions + end + def test_const + assert_equal Array , @compiler.constants.class + end + end +end