add seperate builders

remove if with polymorphism for different builders
(easier to understand by naming)
This commit is contained in:
Torsten Ruger 2018-06-29 13:27:57 +03:00
parent 3dffebed3f
commit 86b1edb40c
8 changed files with 73 additions and 37 deletions

View File

@ -27,7 +27,7 @@ module Mom
# Move method name, frame and arguemnt types from the method to the next_message # Move method name, frame and arguemnt types from the method to the next_message
# Get the message from Space and link it. # Get the message from Space and link it.
def to_risc(compiler) def to_risc(compiler)
builder = compiler.builder(false, self) builder = compiler.code_builder(self)
build_with(builder) build_with(builder)
end end

View File

@ -35,7 +35,7 @@ module Mom
def to_risc( compiler ) def to_risc( compiler )
name_ = @name name_ = @name
cache_entry_ = @cache_entry cache_entry_ = @cache_entry
builder = compiler.builder(false, self) builder = compiler.code_builder(self)
builder.build do builder.build do
word << name_ word << name_
cache_entry << cache_entry_ cache_entry << cache_entry_

View File

@ -2,9 +2,15 @@ module Risc
# A Builder is used to generate code, either by using it's api, or dsl # 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. # 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 class Builder
attr_reader :built , :compiler attr_reader :built , :compiler
@ -12,10 +18,8 @@ module Risc
# pass a compiler, to which instruction are added (usually) # pass a compiler, to which instruction are added (usually)
# second arg determines weather instructions are added (default true) # second arg determines weather instructions are added (default true)
# call build with a block to build # call build with a block to build
def initialize(compiler, auto_add , for_source) def initialize(compiler, for_source)
@compiler = compiler @compiler = compiler
@auto_add = auto_add
@built = nil
@source = for_source @source = for_source
@source_used = false @source_used = false
@names = {} @names = {}
@ -60,6 +64,7 @@ module Risc
# names (that ruby would resolve to a variable/method) are converted # names (that ruby would resolve to a variable/method) are converted
# to registers. << means assignment and [] is supported both on # 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. # 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 # Basically this allows to create LoadConstant, RegToSlot, SlotToReg and
# Transfer instructions with extremely readable code. # Transfer instructions with extremely readable code.
# example: # example:
@ -68,21 +73,14 @@ module Risc
# #
# build result is available as built, but also gets added to compiler, if the # build result is available as built, but also gets added to compiler, if the
# builder is created with default args # builder is created with default args
#
def build(&block) def build(&block)
instance_eval(&block) instance_eval(&block)
@built @built
end 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) def add_code(ins)
return @compiler.add_code(ins) if @auto_add raise "Must be implemented in subclass #{self}"
if(@built)
@built << ins
else
@built = ins
end
end end
# move a machine int from register "from" to a Parfait::Integer in register "to" # move a machine int from register "from" to a Parfait::Integer in register "to"
@ -213,5 +211,38 @@ module Risc
return index return index
end 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 end

View File

@ -8,7 +8,7 @@ module Risc
def div4(context) def div4(context)
source = "div4" source = "div4"
compiler = compiler_for(:Integer,:div4 ,{}) compiler = compiler_for(:Integer,:div4 ,{})
builder = compiler.builder(true, compiler.method) builder = compiler.compiler_builder(compiler.method)
me = builder.add_known( :receiver ) me = builder.add_known( :receiver )
builder.reduce_int( source , me ) builder.reduce_int( source , me )
two = compiler.use_reg :fixnum , 2 two = compiler.use_reg :fixnum , 2
@ -33,7 +33,7 @@ module Risc
end end
def comparison( operator ) def comparison( operator )
compiler = compiler_for(:Integer, operator ,{other: :Integer}) 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") 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)}") 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)}") merge_label = Risc.label(compiler.method , "merge_label_#{builder.object_id.to_s(16)}")
@ -63,7 +63,7 @@ module Risc
end end
def operator_method( op_sym ) def operator_method( op_sym )
compiler = compiler_for(:Integer, op_sym ,{other: :Integer}) 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") 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 me", me )
builder.reduce_int( op_sym.to_s + " fix arg", other ) builder.reduce_int( op_sym.to_s + " fix arg", other )
@ -76,7 +76,7 @@ module Risc
def div10( context ) def div10( context )
s = "div_10 " s = "div_10 "
compiler = compiler_for(:Integer,:div10 ,{}) 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 #FIX: this could load receiver once, reduce and then transfer twice
me = builder.add_known( :receiver ) me = builder.add_known( :receiver )
tmp = builder.add_known( :receiver ) tmp = builder.add_known( :receiver )

View File

@ -9,7 +9,7 @@ module Risc
# (this method returns a new method off course, like all builtin) # (this method returns a new method off course, like all builtin)
def get_internal_word( context ) def get_internal_word( context )
compiler = compiler_for(:Object , :get_internal_word ,{at: :Integer}) 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" source = "get_internal_word"
me , index = builder.self_and_int_arg(source) me , index = builder.self_and_int_arg(source)
# reduce me to me[index] # reduce me to me[index]
@ -25,7 +25,7 @@ module Risc
def set_internal_word( context ) def set_internal_word( context )
compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, :value => :Object} ) compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, :value => :Object} )
source = "set_internal_word" source = "set_internal_word"
builder = compiler.builder(true, compiler.method) builder = compiler.compiler_builder(compiler.method)
me , index = builder.self_and_int_arg(source) me , index = builder.self_and_int_arg(source)
value = builder.load_int_arg_at(source , 1) value = builder.load_int_arg_at(source , 1)
# do the set # do the set
@ -38,7 +38,7 @@ module Risc
# Even if it's just this one, sys_exit (later raise) # Even if it's just this one, sys_exit (later raise)
def _method_missing( context ) def _method_missing( context )
compiler = compiler_for(:Object,:method_missing ,{}) 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 return compiler.method
end end
@ -48,7 +48,7 @@ module Risc
def __init__ context def __init__ context
compiler = MethodCompiler.compiler_for_class(:Object,:__init__ , compiler = MethodCompiler.compiler_for_class(:Object,:__init__ ,
Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({})) Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({}))
builder = compiler.builder(true, compiler.method) builder = compiler.compiler_builder(compiler.method)
builder.build do builder.build do
space << Parfait.object_space space << Parfait.object_space
message << space[:first_message] message << space[:first_message]
@ -87,7 +87,7 @@ module Risc
def exit( context ) def exit( context )
compiler = compiler_for(:Object,:exit ,{}) compiler = compiler_for(:Object,:exit ,{})
builder = compiler.builder(true, compiler.method) builder = compiler.compiler_builder(compiler.method)
exit_sequence(builder) exit_sequence(builder)
return compiler.method return compiler.method
end end

View File

@ -6,7 +6,7 @@ module Risc
def putstring( context) def putstring( context)
compiler = compiler_for(:Word , :putstring ,{}) 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 ) builder.add_slot_to_reg( "putstring" , :message , :receiver , :new_message )
index = Parfait::Word.get_length_index index = Parfait::Word.get_length_index
reg = RegisterValue.new(:r2 , :Integer) reg = RegisterValue.new(:r2 , :Integer)
@ -21,7 +21,7 @@ module Risc
def get_internal_byte( context) def get_internal_byte( context)
compiler = compiler_for(:Word , :get_internal_byte , {at: :Integer}) compiler = compiler_for(:Word , :get_internal_byte , {at: :Integer})
source = "get_internal_byte" source = "get_internal_byte"
builder = compiler.builder(true, compiler.method) builder = compiler.compiler_builder(compiler.method)
me , index = builder.self_and_int_arg(source) me , index = builder.self_and_int_arg(source)
builder.reduce_int( source + " fix arg", index ) builder.reduce_int( source + " fix arg", index )
# reduce me to me[index] # reduce me to me[index]
@ -39,7 +39,7 @@ module Risc
def set_internal_byte( context ) def set_internal_byte( context )
compiler = compiler_for(:Word, :set_internal_byte , {at: :Integer , :value => :Integer} ) compiler = compiler_for(:Word, :set_internal_byte , {at: :Integer , :value => :Integer} )
source = "set_internal_byte" source = "set_internal_byte"
builder = compiler.builder(true, compiler.method) builder = compiler.compiler_builder(compiler.method)
me , index = builder.self_and_int_arg(source) me , index = builder.self_and_int_arg(source)
value = builder.load_int_arg_at(source , 1 ) value = builder.load_int_arg_at(source , 1 )
builder.reduce_int( source + " fix me", value ) builder.reduce_int( source + " fix me", value )

View File

@ -106,11 +106,16 @@ module Risc
builder.build(&block) builder.build(&block)
end end
# return a new builder that uses this compiler # return a new code builder that uses this compiler
# must specify whether to add code automatically to compiler # CodeBuilder returns code after building
# second arg is the source for which to build, either method or mom::instruction def code_builder( source)
def builder( auto_add , source) CodeBuilder.new(self , source)
Builder.new(self , auto_add , source) end
# return a CompilerBuilder
# CompilerBuilder adds the generated code to the compiler
def compiler_builder( source)
CompilerBuilder.new(self , source)
end end
end end
end end

View File

@ -1,12 +1,12 @@
require_relative "../helper" require_relative "../helper"
module Risc module Risc
class TestBuilderFalse < MiniTest::Test class TestCodeBuilder < MiniTest::Test
def setup def setup
Risc.machine.boot Risc.machine.boot
init = Parfait.object_space.get_init 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") @label = Risc.label("source","name")
end end
def test_has_build def test_has_build
@ -97,12 +97,12 @@ module Risc
assert_equal :Space , op.left.type assert_equal :Space , op.left.type
end end
end end
class TestBuilderTrue < MiniTest::Test class TestCompilerBuilder < MiniTest::Test
def setup def setup
Risc.machine.boot Risc.machine.boot
@init = Parfait.object_space.get_init @init = Parfait.object_space.get_init
@builder = Risc::MethodCompiler.new( @init ).builder(true, @init) @builder = Risc::MethodCompiler.new( @init ).compiler_builder(@init)
end end
def test_inserts_built def test_inserts_built
r1 = RegisterValue.new(:r1 , :Space) r1 = RegisterValue.new(:r1 , :Space)