diff --git a/lib/mom/instruction/message_setup.rb b/lib/mom/instruction/message_setup.rb index cb6ef6d9..ba9c36f6 100644 --- a/lib/mom/instruction/message_setup.rb +++ b/lib/mom/instruction/message_setup.rb @@ -27,7 +27,7 @@ module Mom # Move method name, frame and arguemnt types from the method to the next_message # Get the message from Space and link it. def to_risc(compiler) - builder = compiler.builder(false, self) + builder = compiler.code_builder(self) build_with(builder) end diff --git a/lib/mom/instruction/resolve_method.rb b/lib/mom/instruction/resolve_method.rb index 95d7fa46..d3e0a3ee 100644 --- a/lib/mom/instruction/resolve_method.rb +++ b/lib/mom/instruction/resolve_method.rb @@ -35,7 +35,7 @@ module Mom def to_risc( compiler ) name_ = @name cache_entry_ = @cache_entry - builder = compiler.builder(false, self) + builder = compiler.code_builder(self) builder.build do word << name_ cache_entry << cache_entry_ diff --git a/lib/risc/builder.rb b/lib/risc/builder.rb index 7634ffa7..48911166 100644 --- a/lib/risc/builder.rb +++ b/lib/risc/builder.rb @@ -2,9 +2,15 @@ module Risc # A Builder is used to generate code, either by using it's api, or dsl # - # The code that is generated can be added to the comiled method, ie to the compiler. + # There are two subclasses of Builder, depending of what one wants to do with the + # generated code. + # + # CompilerBuilder: The code is added to the method_compiler. # This is used to generate the builtin methods. - # Or the code can be stored up and returned. This is used in Mom::to_risc methods + # + # CodeBuilder: The code can be stored up and returned. + # This is used in Mom::to_risc methods + # class Builder attr_reader :built , :compiler @@ -12,10 +18,8 @@ module Risc # pass a compiler, to which instruction are added (usually) # second arg determines weather instructions are added (default true) # call build with a block to build - def initialize(compiler, auto_add , for_source) + def initialize(compiler, for_source) @compiler = compiler - @auto_add = auto_add - @built = nil @source = for_source @source_used = false @names = {} @@ -60,6 +64,7 @@ module Risc # names (that ruby would resolve to a variable/method) are converted # to registers. << means assignment and [] is supported both on # L and R values (but only one at a time). R values may also be constants. + # # Basically this allows to create LoadConstant, RegToSlot, SlotToReg and # Transfer instructions with extremely readable code. # example: @@ -68,21 +73,14 @@ module Risc # # build result is available as built, but also gets added to compiler, if the # builder is created with default args + # def build(&block) instance_eval(&block) @built end - # adding code to the builder either stores it in the built variable - # or adds it straight to the compiler. - # Depending on wether auto_add was given in construction. def add_code(ins) - return @compiler.add_code(ins) if @auto_add - if(@built) - @built << ins - else - @built = ins - end + raise "Must be implemented in subclass #{self}" end # move a machine int from register "from" to a Parfait::Integer in register "to" @@ -213,5 +211,38 @@ module Risc return index end + class CodeBuilder < Builder + + attr_reader :built + def initialize(compiler, for_source) + super + @built = nil + end + + def build(&block) + super + @built + end + + # CodeBuilder stores the code. + # The code can be access through the @built instance, and is returned + # from build method + def add_code(ins) + if(@built) + @built << ins + else + @built = ins + end + end + end + + # A CompilerBuilder adds the generated code to the MethodCompiler. + # + class CompilerBuilder < Builder + # add code straight to the compiler + def add_code(ins) + return @compiler.add_code(ins) + end + end end diff --git a/lib/risc/builtin/integer.rb b/lib/risc/builtin/integer.rb index e404cabc..8a0c9936 100644 --- a/lib/risc/builtin/integer.rb +++ b/lib/risc/builtin/integer.rb @@ -8,7 +8,7 @@ module Risc def div4(context) source = "div4" compiler = compiler_for(:Integer,:div4 ,{}) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) me = builder.add_known( :receiver ) builder.reduce_int( source , me ) two = compiler.use_reg :fixnum , 2 @@ -33,7 +33,7 @@ module Risc end def comparison( operator ) compiler = compiler_for(:Integer, operator ,{other: :Integer}) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) me , other = builder.self_and_int_arg("#{operator} load receiver and arg") false_label = Risc.label(compiler.method , "false_label_#{builder.object_id.to_s(16)}") merge_label = Risc.label(compiler.method , "merge_label_#{builder.object_id.to_s(16)}") @@ -63,7 +63,7 @@ module Risc end def operator_method( op_sym ) compiler = compiler_for(:Integer, op_sym ,{other: :Integer}) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) me , other = builder.self_and_int_arg(op_sym.to_s + "load receiver and arg") builder.reduce_int( op_sym.to_s + " fix me", me ) builder.reduce_int( op_sym.to_s + " fix arg", other ) @@ -76,7 +76,7 @@ module Risc def div10( context ) s = "div_10 " compiler = compiler_for(:Integer,:div10 ,{}) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) #FIX: this could load receiver once, reduce and then transfer twice me = builder.add_known( :receiver ) tmp = builder.add_known( :receiver ) diff --git a/lib/risc/builtin/object.rb b/lib/risc/builtin/object.rb index 61aaafdf..0361dc57 100644 --- a/lib/risc/builtin/object.rb +++ b/lib/risc/builtin/object.rb @@ -9,7 +9,7 @@ module Risc # (this method returns a new method off course, like all builtin) def get_internal_word( context ) compiler = compiler_for(:Object , :get_internal_word ,{at: :Integer}) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) source = "get_internal_word" me , index = builder.self_and_int_arg(source) # reduce me to me[index] @@ -25,7 +25,7 @@ module Risc def set_internal_word( context ) compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, :value => :Object} ) source = "set_internal_word" - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) me , index = builder.self_and_int_arg(source) value = builder.load_int_arg_at(source , 1) # do the set @@ -38,7 +38,7 @@ module Risc # Even if it's just this one, sys_exit (later raise) def _method_missing( context ) compiler = compiler_for(:Object,:method_missing ,{}) - emit_syscall( compiler.builder(true, compiler.method) , :exit ) + emit_syscall( compiler.compiler_builder(compiler.method) , :exit ) return compiler.method end @@ -48,7 +48,7 @@ module Risc def __init__ context compiler = MethodCompiler.compiler_for_class(:Object,:__init__ , Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({})) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) builder.build do space << Parfait.object_space message << space[:first_message] @@ -87,7 +87,7 @@ module Risc def exit( context ) compiler = compiler_for(:Object,:exit ,{}) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) exit_sequence(builder) return compiler.method end diff --git a/lib/risc/builtin/word.rb b/lib/risc/builtin/word.rb index 22667512..51e14101 100644 --- a/lib/risc/builtin/word.rb +++ b/lib/risc/builtin/word.rb @@ -6,7 +6,7 @@ module Risc def putstring( context) compiler = compiler_for(:Word , :putstring ,{}) - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) builder.add_slot_to_reg( "putstring" , :message , :receiver , :new_message ) index = Parfait::Word.get_length_index reg = RegisterValue.new(:r2 , :Integer) @@ -21,7 +21,7 @@ module Risc def get_internal_byte( context) compiler = compiler_for(:Word , :get_internal_byte , {at: :Integer}) source = "get_internal_byte" - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) me , index = builder.self_and_int_arg(source) builder.reduce_int( source + " fix arg", index ) # reduce me to me[index] @@ -39,7 +39,7 @@ module Risc def set_internal_byte( context ) compiler = compiler_for(:Word, :set_internal_byte , {at: :Integer , :value => :Integer} ) source = "set_internal_byte" - builder = compiler.builder(true, compiler.method) + builder = compiler.compiler_builder(compiler.method) me , index = builder.self_and_int_arg(source) value = builder.load_int_arg_at(source , 1 ) builder.reduce_int( source + " fix me", value ) diff --git a/lib/risc/method_compiler.rb b/lib/risc/method_compiler.rb index a328558d..b3e2e84f 100644 --- a/lib/risc/method_compiler.rb +++ b/lib/risc/method_compiler.rb @@ -106,11 +106,16 @@ module Risc builder.build(&block) end - # return a new builder that uses this compiler - # must specify whether to add code automatically to compiler - # second arg is the source for which to build, either method or mom::instruction - def builder( auto_add , source) - Builder.new(self , auto_add , source) + # return a new code builder that uses this compiler + # CodeBuilder returns code after building + def code_builder( source) + CodeBuilder.new(self , source) + end + + # return a CompilerBuilder + # CompilerBuilder adds the generated code to the compiler + def compiler_builder( source) + CompilerBuilder.new(self , source) end end end diff --git a/test/risc/test_builder.rb b/test/risc/test_builder.rb index 903be235..e7522ba5 100644 --- a/test/risc/test_builder.rb +++ b/test/risc/test_builder.rb @@ -1,12 +1,12 @@ require_relative "../helper" module Risc - class TestBuilderFalse < MiniTest::Test + class TestCodeBuilder < MiniTest::Test def setup Risc.machine.boot init = Parfait.object_space.get_init - @builder = Risc::MethodCompiler.new( init ).builder(false , init) + @builder = Risc::MethodCompiler.new( init ).code_builder(init) @label = Risc.label("source","name") end def test_has_build @@ -97,12 +97,12 @@ module Risc assert_equal :Space , op.left.type end end - class TestBuilderTrue < MiniTest::Test + class TestCompilerBuilder < MiniTest::Test def setup Risc.machine.boot @init = Parfait.object_space.get_init - @builder = Risc::MethodCompiler.new( @init ).builder(true, @init) + @builder = Risc::MethodCompiler.new( @init ).compiler_builder(@init) end def test_inserts_built r1 = RegisterValue.new(:r1 , :Space)