From e396807ee505ef23280e6883af0edb3ed72b21af Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Fri, 6 Apr 2018 14:21:38 +0300 Subject: [PATCH] start work on dsl so i can read my own code --- lib/mom/instruction/message_setup.rb | 4 + lib/risc.rb | 3 +- lib/risc/{register_value.rb => builder.rb} | 151 +++++++-------------- lib/risc/risc_value.rb | 89 ++++++++++++ test/risc/test_builder.rb | 6 + test/risc/test_risc_value.rb | 6 + 6 files changed, 158 insertions(+), 101 deletions(-) rename lib/risc/{register_value.rb => builder.rb} (52%) create mode 100644 lib/risc/risc_value.rb create mode 100644 test/risc/test_builder.rb create mode 100644 test/risc/test_risc_value.rb diff --git a/lib/mom/instruction/message_setup.rb b/lib/mom/instruction/message_setup.rb index ee76e694..3c864518 100644 --- a/lib/mom/instruction/message_setup.rb +++ b/lib/mom/instruction/message_setup.rb @@ -58,6 +58,10 @@ module Mom # use given message register # return instructions to do this def get_message_to( compiler , message) + Risc.build(compiler) do + space << Parfait.object_space + end + space = compiler.use_reg(:Space) risc = Risc.load_constant("message setup move method" , Parfait.object_space ,space) risc << Risc.slot_to_reg(source + "get next message" , space , :first_message , message) diff --git a/lib/risc.rb b/lib/risc.rb index db19875b..6e091c30 100644 --- a/lib/risc.rb +++ b/lib/risc.rb @@ -27,6 +27,7 @@ end require_relative "risc/instruction" -require_relative "risc/register_value" +require_relative "risc/risc_value" require_relative "risc/text_writer" require_relative "risc/builtin/space" +require_relative "risc/builder" diff --git a/lib/risc/register_value.rb b/lib/risc/builder.rb similarity index 52% rename from lib/risc/register_value.rb rename to lib/risc/builder.rb index d333d2a9..0cb9dc58 100644 --- a/lib/risc/register_value.rb +++ b/lib/risc/builder.rb @@ -1,112 +1,25 @@ module Risc - # RiscValue is like a variable name, a storage location. The location is a register off course. + class Builder - class RiscValue - - attr_accessor :symbol , :type , :value - - def initialize r , type , value = nil - raise "wrong type for register init #{r}" unless r.is_a? Symbol - raise "double r #{r}" if r.to_s[0,1] == "rr" - raise "not reg #{r}" unless self.class.look_like_reg r - @type = type - @symbol = r - @value = value + def initialize(compiler) + @compiler = compiler end - def to_s - s = "#{symbol}:#{type}" - s += ":#{value}" if value - s + def method_missing(*args) + super if args.length != 1 + name = args[0].to_s.capitalize.to_sym + type = Risc.resolve_type(name , @compiler) + reg = @compiler.use_reg( type ) + puts reg + reg end - - def reg_no - @symbol.to_s[1 .. -1].to_i - end - - def self.look_like_reg is_it - return true if is_it.is_a? RiscValue - return false unless is_it.is_a? Symbol - if( [:lr , :pc].include? is_it ) - return true - end - if( (is_it.to_s.length <= 3) and (is_it.to_s[0] == "r")) - # could tighten this by checking that the rest is a number - return true - end - return false - end - - def == other - return false if other.nil? - return false if other.class != RiscValue - symbol == other.symbol - end - - #helper method to calculate with register symbols - def next_reg_use( type , value = nil ) - int = @symbol[1,3].to_i - raise "No more registers #{self}" if int > 8 - sym = "r#{int + 1}".to_sym - RiscValue.new( sym , type, value) - end - - def sof_reference_name - @symbol - end - end - # Here we define the mapping from virtual machine objects, to register machine registers - # - - # The register we use to store the current message object is :r0 - def self.message_reg - RiscValue.new :r0 , :Message + class RValue end - - # The register we use to store the new message object is :r3 - # The new message is the one being built, to be sent - def self.new_message_reg - RiscValue.new :r1 , :Message - end - - # The first scratch register. There is a next_reg_use to get a next and next. - # Current thinking is that scratch is schatch between instructions - def self.tmp_reg( type , value = nil) - RiscValue.new :r1 , type , value - end - - # The first arg is a class name (possibly lowercase) and the second an instance variable name. - # By looking up the class and the type for that class, we can resolve the instance - # variable name to an index. - # The class can be mapped to a register, and so we get a memory address (reg+index) - # Third arg, compiler, is only needed to resolve receiver/arguments/frame - def self.resolve_to_index(object , variable_name ,compiler = nil) - return variable_name if variable_name.is_a?(Integer) or variable_name.is_a?(RiscValue) - object = object.type if object.is_a?(RiscValue) - case object - when :frame - type = compiler.method.frame_type - when :message , :next_message , :caller - type = Parfait.object_space.get_class_by_name(:Message).instance_type - when :arguments - type = compiler.method.arguments_type - when :receiver - type = compiler.method.for_type - when Parfait::Object - type = Parfait.object_space.get_class_by_name( object.class.name.split("::").last.to_sym).instance_type - when Symbol - clazz = Parfait.object_space.get_class_by_name(object) - raise "Not implemented/found object #{object}:#{object.class}" unless clazz - type = clazz.instance_type - else - raise "Not implemented/found object #{object}:#{object.class}" - end - index = type.variable_index(variable_name) - raise "Index not found for #{variable_name} in #{object} of type #{type}" unless index - return index + def self.build(compiler, &block) + Builder.new(compiler).instance_eval( &block ) end # if a symbol is given, it may be the message or the new_message. @@ -126,4 +39,42 @@ module Risc end end + # The first arg is a class name (possibly lowercase) and the second an instance variable name. + def self.resolve_type( object , compiler ) + object = object.type if object.is_a?(RiscValue) + case object + when :frame + type = compiler.method.frame_type + when :message , :next_message , :caller + type = Parfait.object_space.get_class_by_name(:Message).instance_type + when :arguments + type = compiler.method.arguments_type + when :receiver + type = compiler.method.for_type + when Parfait::Object + type = Parfait.object_space.get_class_by_name( object.class.name.split("::").last.to_sym).instance_type + when Symbol + clazz = Parfait.object_space.get_class_by_name(object) + raise "Not implemented/found object #{object}:#{object.class}" unless clazz + type = clazz.instance_type + else + raise "Not implemented/found object #{object}:#{object.class}" + end + return type + end + + # The first arg is a class name (possibly lowercase) and the second an instance variable name. + # By looking up the class and the type for that class, we can resolve the instance + # variable name to an index. + # The class can be mapped to a register, and so we get a memory address (reg+index) + # Third arg, compiler, is only needed to resolve receiver/arguments/frame + def self.resolve_to_index(object , variable_name ,compiler = nil) + return variable_name if variable_name.is_a?(Integer) or variable_name.is_a?(RiscValue) + type = resolve_type(object , compiler) + index = type.variable_index(variable_name) + raise "Index not found for #{variable_name} in #{object} of type #{type}" unless index + return index + end + + end diff --git a/lib/risc/risc_value.rb b/lib/risc/risc_value.rb new file mode 100644 index 00000000..9c38a9f1 --- /dev/null +++ b/lib/risc/risc_value.rb @@ -0,0 +1,89 @@ +module Risc + + # RiscValue is like a variable name, a storage location. The location is a register off course. + + class RiscValue + + attr_accessor :symbol , :type , :value + + def initialize r , type , value = nil + raise "wrong type for register init #{r}" unless r.is_a? Symbol + raise "double r #{r}" if r.to_s[0,1] == "rr" + raise "not reg #{r}" unless self.class.look_like_reg r + @type = type + @symbol = r + @value = value + end + + def to_s + s = "#{symbol}:#{type}" + s += ":#{value}" if value + s + end + + def reg_no + @symbol.to_s[1 .. -1].to_i + end + + def self.look_like_reg is_it + return true if is_it.is_a? RiscValue + return false unless is_it.is_a? Symbol + if( [:lr , :pc].include? is_it ) + return true + end + if( (is_it.to_s.length <= 3) and (is_it.to_s[0] == "r")) + # could tighten this by checking that the rest is a number + return true + end + return false + end + + def == other + return false if other.nil? + return false if other.class != RiscValue + symbol == other.symbol + end + + #helper method to calculate with register symbols + def next_reg_use( type , value = nil ) + int = @symbol[1,3].to_i + raise "No more registers #{self}" if int > 8 + sym = "r#{int + 1}".to_sym + RiscValue.new( sym , type, value) + end + + def sof_reference_name + @symbol + end + + def <<( load ) + puts "LOAD #{load}" + case load + when RValue + raise "not yet" + when Parfait::Object + Risc.load_constant("#{load.class} to #{self.type}" , load , self) + else + raise "not implemented" + end + end + end + + # The register we use to store the current message object is :r0 + def self.message_reg + RiscValue.new :r0 , :Message + end + + # The register we use to store the new message object is :r3 + # The new message is the one being built, to be sent + def self.new_message_reg + RiscValue.new :r1 , :Message + end + + # The first scratch register. There is a next_reg_use to get a next and next. + # Current thinking is that scratch is schatch between instructions + def self.tmp_reg( type , value = nil) + RiscValue.new :r1 , type , value + end + +end diff --git a/test/risc/test_builder.rb b/test/risc/test_builder.rb new file mode 100644 index 00000000..5e742b76 --- /dev/null +++ b/test/risc/test_builder.rb @@ -0,0 +1,6 @@ +require_relative "../helper" + +module Risc + class TestBuilder < MiniTest::Test + end +end diff --git a/test/risc/test_risc_value.rb b/test/risc/test_risc_value.rb new file mode 100644 index 00000000..a2a30610 --- /dev/null +++ b/test/risc/test_risc_value.rb @@ -0,0 +1,6 @@ +require_relative "../helper" + +module Risc + class TestRegisterValue < MiniTest::Test + end +end