diff --git a/lib/mom/block_compiler.rb b/lib/mom/block_compiler.rb new file mode 100644 index 00000000..7cef35b3 --- /dev/null +++ b/lib/mom/block_compiler.rb @@ -0,0 +1,60 @@ +module Mom + + # A BlockCompiler is much like a MehtodCompiler, exept for blocks + # + class BlockCompiler < CallableCompiler + + attr_reader :block , :mom_instructions + alias :block :callable + + def initialize( block , method) + @method = method + super(block) + end + + def source_name + "#{@method.self_type.name}.init" + end + + def to_risc(in_method) + risc_compiler = Risc::BlockCompiler.new(@callable , in_method , mom_instructions) + instructions_to_risc(risc_compiler) + #recursive blocks not done + risc_compiler + end + + # resolve the type of the slot, by inferring from it's name, using the type + # scope related slots are resolved by the compiler by method/block + # + # This mainly calls super, and only for :caller adds extra info + # Using the info, means assuming that the block is not passed around (FIXME in 2020) + def slot_type( slot , type) + new_type = super + if slot == :caller + extra_info = { type_frame: @method.frame_type , + type_arguments: @method.arguments_type , + type_self: @method.self_type} + end + return new_type , extra_info + end + # determine how given name need to be accsessed. + # For blocks the options are args or frame + # or then the methods arg or frame + def slot_type_for(name) + if @callable.arguments_type.variable_index(name) + slot_def = [:arguments] + elsif @callable.frame_type.variable_index(name) + slot_def = [:frame] + elsif @method.arguments_type.variable_index(name) + slot_def = [:caller , :caller ,:arguments ] + elsif @method.frame_type.variable_index(name) + slot_def = [:caller ,:caller , :frame ] + elsif + raise "no variable #{name} , need to resolve at runtime" + end + slot_def << name + end + + + end +end diff --git a/lib/risc/builtin.rb b/lib/mom/builtin.rb similarity index 69% rename from lib/risc/builtin.rb rename to lib/mom/builtin.rb index b9c48b36..f135a2f8 100644 --- a/lib/risc/builtin.rb +++ b/lib/mom/builtin.rb @@ -1,20 +1,32 @@ -require_relative "builtin/compile_helper" +module Mom + module Builtin + module CompileHelper + + def compiler_for( clazz_name , method_name , arguments , locals = {}) + frame = Parfait::NamedList.type_for( locals ) + args = Parfait::NamedList.type_for( arguments ) + Mom::MethodCompiler.compiler_for_class(clazz_name , method_name , args, frame ) + end + end + end +end + require_relative "builtin/space" require_relative "builtin/integer" require_relative "builtin/object" require_relative "builtin/word" -module Risc +module Mom module Builtin # classes have booted, now create a minimal set of functions # minimal means only that which can not be coded in ruby # Methods are grabbed from respective modules by sending the method name. - # This should return the implementation of the method (ie a method object), + # This should return the implementation of the method (ie a method compiler), # not actually try to implement it(as that's impossible in ruby) # - # When no main has been compiled, we will add an empty main (for testing) - # - def self.boot_functions(add_main = false) + # We create an empty main for init to jump to, if no code is compiled, that just returns + # See Builtin directory readme and module + def self.boot_functions() # TODO go through the virtual parfait layer and adjust function names # to what they really are compilers = [] @@ -25,8 +37,8 @@ module Risc end obj_type = space.get_type_by_class_name(:Object) - [ :get_internal_word , :set_internal_word , :_method_missing, - :exit , :__init__].each do |f| + [ :__init__ , :exit , :_method_missing, :get_internal_word , + :set_internal_word ].each do |f| compilers << compiler_for( obj_type , Object , f) end @@ -39,7 +51,7 @@ module Risc Risc.operators.each do |op| compilers << operator_compiler( int_type , op) end - [:putint, :div4, :div10 , :<,:<= , :>=, :>].each do |f| #div4 is just a forward declaration + [ :div4, :<,:<= , :>=, :> , :div10 ].each do |f| #div4 is just a forward declaration compilers << compiler_for( int_type , Integer , f) end compilers diff --git a/lib/risc/builtin/README.md b/lib/mom/builtin/README.md similarity index 100% rename from lib/risc/builtin/README.md rename to lib/mom/builtin/README.md diff --git a/lib/mom/builtin/comparison.rb b/lib/mom/builtin/comparison.rb new file mode 100644 index 00000000..841482ce --- /dev/null +++ b/lib/mom/builtin/comparison.rb @@ -0,0 +1,34 @@ +module Mom + module Builtin + class Comparison < ::Mom::Instruction + attr_reader :operator + def initialize(name , operator) + super(name) + @operator = operator + end + def to_risc(compiler) + builder = compiler.builder(compiler.source) + operator = @operator # make accessible in block + builder.build do + integer! << message[:receiver] + integer.reduce_int + integer_reg! << message[:arguments] + integer_reg << integer_reg[Parfait::NamedList.type_length + 0] #"other" is at index 0 + integer_reg.reduce_int + swap_names(:integer , :integer_reg) if(operator.to_s.start_with?('<') ) + integer.op :- , integer_reg + if_minus false_label + if_zero( false_label ) if operator.to_s.length == 1 + object! << Parfait.object_space.true_object + branch merge_label + add_code false_label + object << Parfait.object_space.false_object + add_code merge_label + message[:return_value] << object + end + return compiler + end + end + + end +end diff --git a/lib/mom/builtin/div10.rb b/lib/mom/builtin/div10.rb new file mode 100644 index 00000000..0d54736d --- /dev/null +++ b/lib/mom/builtin/div10.rb @@ -0,0 +1,65 @@ +module Mom + module Builtin + class Div10 < ::Mom::Instruction + def to_risc(compiler) + s = "div_10 " + builder = compiler.builder(compiler.source) + integer_tmp = builder.allocate_int + builder.build do + integer_self! << message[:receiver] + integer_self.reduce_int + integer_1! << integer_self + integer_reg! << integer_self + + integer_const! << 1 + integer_1.op :>> , integer_const + + integer_const << 2 + integer_reg.op :>> , integer_const + integer_reg.op :+ , integer_1 + + integer_const << 4 + integer_1 << integer_reg + integer_reg.op :>> , integer_1 + + integer_reg.op :+ , integer_1 + + integer_const << 8 + integer_1 << integer_reg + integer_1.op :>> , integer_const + + integer_reg.op :+ , integer_1 + + integer_const << 16 + integer_1 << integer_reg + integer_1.op :>> , integer_const + + integer_reg.op :+ , integer_1 + + integer_const << 3 + integer_reg.op :>> , integer_const + + integer_const << 10 + integer_1 << integer_reg + integer_1.op :* , integer_const + + integer_self.op :- , integer_1 + integer_1 << integer_self + + integer_const << 6 + integer_1.op :+ , integer_const + + integer_const << 4 + integer_1.op :>> , integer_const + + integer_reg.op :+ , integer_1 + + integer_tmp[Parfait::Integer.integer_index] << integer_reg + message[:return_value] << integer_tmp + + end + return compiler + end + end + end +end diff --git a/lib/mom/builtin/div4.rb b/lib/mom/builtin/div4.rb new file mode 100644 index 00000000..b41e04ea --- /dev/null +++ b/lib/mom/builtin/div4.rb @@ -0,0 +1,19 @@ +module Mom + module Builtin + class Div4 < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + integer_tmp = builder.allocate_int + builder.build do + integer_self! << message[:receiver] + integer_self.reduce_int + integer_1! << 2 + integer_self.op :>> , integer_1 + integer_tmp[Parfait::Integer.integer_index] << integer_self + message[:return_value] << integer_tmp + end + return compiler + end + end + end +end diff --git a/lib/mom/builtin/exit.rb b/lib/mom/builtin/exit.rb new file mode 100644 index 00000000..aa129909 --- /dev/null +++ b/lib/mom/builtin/exit.rb @@ -0,0 +1,12 @@ +module Mom + module Builtin + class Exit < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + builder.prepare_int_return # makes integer_tmp variable as return + Builtin.exit_sequence(builder) + return compiler + end + end + end +end diff --git a/lib/mom/builtin/get_internal_byte.rb b/lib/mom/builtin/get_internal_byte.rb new file mode 100644 index 00000000..89732a1e --- /dev/null +++ b/lib/mom/builtin/get_internal_byte.rb @@ -0,0 +1,20 @@ +module Mom + module Builtin + class GetInternalByte < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + integer_tmp = builder.allocate_int + builder.build do + object! << message[:receiver] + integer! << message[:arguments] + integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 + integer.reduce_int + object <= object[integer] + integer_tmp[Parfait::Integer.integer_index] << object + message[:return_value] << integer_tmp + end + return compiler + end + end + end +end diff --git a/lib/mom/builtin/get_internal_word.rb b/lib/mom/builtin/get_internal_word.rb new file mode 100644 index 00000000..d6e98f3e --- /dev/null +++ b/lib/mom/builtin/get_internal_word.rb @@ -0,0 +1,16 @@ +module Mom + module Builtin + class GetInternalWord < ::Mom::Instruction + def to_risc(compiler) + compiler.builder(compiler.source).build do + object! << message[:receiver] + integer! << message[:arguments] + integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 + integer.reduce_int + object << object[integer] + message[:return_value] << object + end + end + end + end +end diff --git a/lib/mom/builtin/init.rb b/lib/mom/builtin/init.rb new file mode 100644 index 00000000..ea1e2204 --- /dev/null +++ b/lib/mom/builtin/init.rb @@ -0,0 +1,36 @@ +module Mom + module Builtin + class Init < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + builder.build do + factory! << Parfait.object_space.get_factory_for(:Message) + message << factory[:next_object] + next_message! << message[:next_message] + factory[:next_object] << next_message + end + + Mom::MessageSetup.new(Parfait.object_space.get_main).build_with( builder ) + + builder.build do + message << message[:next_message] + space? << Parfait.object_space + message[:receiver] << space + end + + exit_label = Risc.label(compiler.source , "#{compiler.receiver_type.object_class.name}.#{compiler.source.name}" ) + ret_tmp = compiler.use_reg(:Label).set_builder(builder) + builder.build do + ret_tmp << exit_label + message[:return_address] << ret_tmp + add_code Risc.function_call( "__init__ issue call" , Parfait.object_space.get_main) + add_code exit_label + end + compiler.reset_regs + Builtin.exit_sequence(builder) + return compiler + end + end + + end +end diff --git a/lib/mom/builtin/integer.rb b/lib/mom/builtin/integer.rb new file mode 100644 index 00000000..139b7297 --- /dev/null +++ b/lib/mom/builtin/integer.rb @@ -0,0 +1,85 @@ +require_relative "div4" +require_relative "div10" +require_relative "operator" +require_relative "comparison" + +module Mom + module Builtin + # integer related kernel functions + # all these functions (return the function they implement) assume interger input + # Also the returned integer object has to be passed in to avoid having to allocate it. + # + # This means the methods will have to be renamed at some point and wrapped + module Integer + module ClassMethods + include CompileHelper + + # div by 4, ie shift right by 2 + # Mostly created for testing at this point, as it is short + # return new int with result + def div4(context) + compiler = compiler_for(:Integer,:div4 ,{}) + compiler.add_code Div4.new("div4") + return compiler + end + + # implemented by the comparison + def >( context ) + comparison( :> ) + end + # implemented by the comparison + def <( context ) + comparison( :< ) + end + # implemented by the comparison + def <=( context ) + comparison( :<= ) + end + # implemented by the comparison + def >=( context ) + comparison( :>= ) + end + + # all (four) comparison operation are quite similar and implemented here + # - reduce the ints (assume int as input) + # - subtract the fixnums + # - check for minus ( < and > ) + # - also check for zero (<= and >=) + # - load true or false object into return, depending on check + # - return + def comparison( operator ) + compiler = compiler_for(:Integer, operator ,{other: :Integer }) + compiler.add_code Comparison.new("comparison" , operator) + return compiler + end + + # implemented all known binary operators that map straight to machine codes + # this function (similar to comparison): + # - unpacks the intergers to fixnum + # - applies the operator (at a risc level) + # - gets a new integer and stores the result + # - returns the new int + def operator_method( op_sym ) + compiler = compiler_for(:Integer, op_sym ,{other: :Integer }) + compiler.add_code Operator.new("operator" , op_sym) + return compiler + end + + # as the name suggests, this devides the integer (self) by ten + # + # This version is lifted from some arm assembler tricks and is _much_ + # faster than the general div versions. I think it was about three + # times less instructions. Useful for itos + # + # In fact it is possible to generate specific div function for any given + # integer and some are even more faster (as eg div4). + def div10( context ) + compiler = compiler_for(:Integer,:div10 ,{}) + compiler.add_code Div10.new("div10") + return compiler + end + end + extend ClassMethods + end + end +end diff --git a/lib/mom/builtin/method_missing.rb b/lib/mom/builtin/method_missing.rb new file mode 100644 index 00000000..f6f15678 --- /dev/null +++ b/lib/mom/builtin/method_missing.rb @@ -0,0 +1,12 @@ +module Mom + module Builtin + class MethodMissing < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + builder.prepare_int_return # makes integer_tmp variable as return + Builtin.emit_syscall( builder , :exit ) + return compiler + end + end + end +end diff --git a/lib/mom/builtin/object.rb b/lib/mom/builtin/object.rb new file mode 100644 index 00000000..401541e4 --- /dev/null +++ b/lib/mom/builtin/object.rb @@ -0,0 +1,107 @@ +require_relative "get_internal_word" +require_relative "set_internal_word" +require_relative "method_missing" +require_relative "init" +require_relative "exit" + +module Mom + module Builtin + class Object + module ClassMethods + include CompileHelper + + # self[index] basically. Index is the first arg + # return is stored in return_value + def get_internal_word( context ) + compiler = compiler_for(:Object , :get_internal_word ,{at: :Integer}) + compiler.add_code GetInternalWord.new("get_internal_word") + return compiler + end + # self[index] = val basically. Index is the first arg , value the second + # return the value passed in + def set_internal_word( context ) + compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, value: :Object} ) + compiler.add_code SetInternalWord.new("set_internal_word") + return compiler + end + + # every object needs a method missing. + # Even if it's just this one, sys_exit (later raise) + def _method_missing( context ) + compiler = compiler_for(:Object,:method_missing ,{}) + compiler.add_code MethodMissing.new("missing") + return compiler + end + + # this is the really really first place the machine starts (apart from the jump here) + # it isn't really a function, ie it is jumped to (not called), exits and may not return + # so it is responsible for initial setup: + # - load fist message, set up Space as receiver + # - call main, ie set up message for that etc + # - exit (exit_sequence) which passes a machine int out to c + def __init__( context ) + compiler = Mom::MethodCompiler.compiler_for_class(:Object,:__init__ , + Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({})) + compiler.add_code Init.new("missing") + return compiler + end + + # the exit function + # mainly calls exit_sequence + def exit( context ) + compiler = compiler_for(:Object,:exit ,{}) + compiler.add_code Exit.new("exit") + return compiler + end + + end + extend ClassMethods + end + + # emit the syscall with given name + # there is a Syscall instruction, but the message has to be saved and restored + def self.emit_syscall( builder , name ) + save_message( builder ) + builder.add_code Risc::Syscall.new("emit_syscall(#{name})", name ) + restore_message(builder) + return unless (@clazz and @method) + builder.add_code Risc.label( "#{@clazz.name}.#{@message.name}" , "return_syscall" ) + end + + # a sort of inline version of exit method. + # Used by exit and __init__ (so it doesn't have to call it) + # Assumes int return value and extracts the fixnum for process exit code + def self.exit_sequence(builder) + save_message( builder ) + builder.build do + message << message[:return_value] + message.reduce_int + add_code Risc::Syscall.new("emit_syscall(exit)", :exit ) + end + end + + # save the current message, as the syscall destroys all context + # + # This relies on linux to save and restore all registers + # + def self.save_message(builder) + r8 = Risc::RegisterValue.new( :r8 , :Message).set_builder(builder) + builder.build {r8 << message} + end + + # restore the message that we save in r8 + # before th restore, the syscall return, a fixnum, is saved + # The caller of this method is assumed to caal prepare_int_return + # so that the return value already has an integer instance + # This instance is filled with os return value + def self.restore_message(builder) + r8 = Risc::RegisterValue.new( :r8 , :Message) + builder.build do + integer_reg! << message + message << r8 + integer_2! << message[:return_value] + integer_2[Parfait::Integer.integer_index] << integer_reg + end + end + end +end diff --git a/lib/mom/builtin/operator.rb b/lib/mom/builtin/operator.rb new file mode 100644 index 00000000..070bb2ee --- /dev/null +++ b/lib/mom/builtin/operator.rb @@ -0,0 +1,28 @@ +module Mom + module Builtin + class Operator < ::Mom::Instruction + attr_reader :operator + def initialize(name , operator) + super(name) + @operator = operator + end + + def to_risc(compiler) + builder = compiler.builder(compiler.source) + integer_tmp = builder.allocate_int + operator = @operator # make accessible in block + builder.build do + integer! << message[:receiver] + integer.reduce_int + integer_reg! << message[:arguments] + integer_reg << integer_reg[Parfait::NamedList.type_length + 0] #"other" is at index 0 + integer_reg.reduce_int + integer.op operator , integer_reg + integer_tmp[Parfait::Integer.integer_index] << integer + message[:return_value] << integer_tmp + end + return compiler + end + end + end +end diff --git a/lib/mom/builtin/putstring.rb b/lib/mom/builtin/putstring.rb new file mode 100644 index 00000000..4bfc7b81 --- /dev/null +++ b/lib/mom/builtin/putstring.rb @@ -0,0 +1,16 @@ +module Mom + module Builtin + class Putstring < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + builder.prepare_int_return # makes integer_tmp variable as return + builder.build do + word! << message[:receiver] + integer! << word[Parfait::Word.get_length_index] + end + Mom::Builtin.emit_syscall( builder , :putstring ) + compiler + end + end + end +end diff --git a/lib/mom/builtin/set_internal_byte.rb b/lib/mom/builtin/set_internal_byte.rb new file mode 100644 index 00000000..36a1eb2e --- /dev/null +++ b/lib/mom/builtin/set_internal_byte.rb @@ -0,0 +1,19 @@ +module Mom + module Builtin + class SetInternalByte < ::Mom::Instruction + def to_risc(compiler) + compiler.builder(compiler.source).build do + word! << message[:receiver] + integer! << message[:arguments] + integer_reg! << integer[Parfait::NamedList.type_length + 1] #"value" is at index 1 + message[:return_value] << integer_reg + integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 + integer.reduce_int + integer_reg.reduce_int + word[integer] <= integer_reg + end + return compiler + end + end + end +end diff --git a/lib/mom/builtin/set_internal_word.rb b/lib/mom/builtin/set_internal_word.rb new file mode 100644 index 00000000..a43b0dcb --- /dev/null +++ b/lib/mom/builtin/set_internal_word.rb @@ -0,0 +1,18 @@ +module Mom + module Builtin + class SetInternalWord < ::Mom::Instruction + def to_risc(compiler) + compiler.builder(compiler.source).build do + object! << message[:receiver] + integer! << message[:arguments] + object_reg! << integer[Parfait::NamedList.type_length + 1] #"value" is at index 1 + integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 + integer.reduce_int + object[integer] << object_reg + message[:return_value] << object_reg + end + return compiler + end + end + end +end diff --git a/lib/risc/builtin/space.rb b/lib/mom/builtin/space.rb similarity index 85% rename from lib/risc/builtin/space.rb rename to lib/mom/builtin/space.rb index c1c16095..61999513 100644 --- a/lib/risc/builtin/space.rb +++ b/lib/mom/builtin/space.rb @@ -1,4 +1,4 @@ -module Risc +module Mom module Builtin class Space module ClassMethods @@ -8,7 +8,6 @@ module Risc # defined here as empty, to be redefined def main(context) compiler = compiler_for(:Space , :main ,{args: :Integer}) - compiler.add_mom( Mom::ReturnSequence.new) return compiler end diff --git a/lib/mom/builtin/word.rb b/lib/mom/builtin/word.rb new file mode 100644 index 00000000..945933d5 --- /dev/null +++ b/lib/mom/builtin/word.rb @@ -0,0 +1,43 @@ +require_relative "get_internal_byte" +require_relative "set_internal_byte" +require_relative "putstring" + +module Mom + module Builtin + module Word + module ClassMethods + include CompileHelper + + # wrapper for the syscall + # io/file currently hardcoded to stdout + # set up registers for syscall, ie + # - pointer in r1 + # - length in r2 + # - emit_syscall (which does the return of an integer, see there) + def putstring( context) + compiler = compiler_for(:Word , :putstring ,{}) + compiler.add_code Putstring.new("putstring") + return compiler + end + # self[index] basically. Index is the first arg > 0 + # return a word sized new int, in return_value + # + # Note: no index (or type) checking. Method should be internal and check before. + # Which means the returned integer could be passed in, instead of allocated. + def get_internal_byte( context) + compiler = compiler_for(:Word , :get_internal_byte , {at: :Integer}) + compiler.add_code GetInternalByte.new("get_internal_byte") + return compiler + end + # self[index] = val basically. Index is the first arg ( >0 , unchecked), + # value the second, which is also returned + def set_internal_byte( context ) + compiler = compiler_for(:Word, :set_internal_byte , {at: :Integer , value: :Integer} ) + compiler.add_code SetInternalByte.new("set_internal_byte") + return compiler + end + end + extend ClassMethods + end + end +end diff --git a/lib/mom/callable_compiler.rb b/lib/mom/callable_compiler.rb new file mode 100644 index 00000000..cef779fa --- /dev/null +++ b/lib/mom/callable_compiler.rb @@ -0,0 +1,104 @@ +module Mom + + # CallableCompiler is used to generate mom instructions. It is an abstact base + # class shared by BlockCompiler and MethodCompiler + + # - mom_instructions: The sequence of mom level instructions that mom was compiled to + # Instructions derive from class Instruction and form a linked list + + class CallableCompiler + + def initialize( callable ) + @callable = callable + @constants = [] + @block_compilers = [] + @mom_instructions = Label.new(source_name, source_name) + @current = start = @mom_instructions + add_code Label.new( source_name, "return_label") + add_code Mom::ReturnSequence.new(source_name) + add_code Label.new( source_name, "unreachable") + @current = start + end + attr_reader :mom_instructions , :constants , :block_compilers , :callable , :current + + def return_label + @mom_instructions.each do |ins| + next unless ins.is_a?(Label) + return ins if ins.name == "return_label" + end + end + + # add a constant (which get created during compilation and need to be linked) + def add_constant(const) + raise "Must be Parfait #{const}" unless const.is_a?(Parfait::Object) + @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 ) + raise "Not an instruction:#{instruction.to_s}:#{instruction.class.name}" unless instruction.is_a?(Mom::Instruction) + new_current = instruction.last #after insertion this point is lost + @current.insert(instruction) #insert after current + @current = new_current + self + end + + # resolve the type of the slot, by inferring from it's name, using the type + # scope related slots are resolved by the compiler by method/block + def slot_type( slot , type) + case slot + when :frame + new_type = self.frame_type + when :arguments + new_type = self.arg_type + when :receiver + new_type = self.receiver_type + when Symbol + new_type = type.type_for(slot) + raise "Not found object #{slot}: in #{type}" unless new_type + else + raise "Not implemented object #{slot}:#{slot.class}" + end + #puts "RESOLVE in #{@type.class_name} #{slot}->#{type}" + return new_type + end + + # return the frame type, ie the blocks frame type + def frame_type + @callable.frame_type + end + + # return the frame type, ie the blocks arguments type + def arg_type + @callable.arguments_type + end + # return the frame type, ie the blocks self_type + def receiver_type + @callable.self_type + end + + private + + # convert al instruction to risc + # method is called by Method/BlockCompiler from to_risc + def instructions_to_risc(risc_compiler) + instruction = mom_instructions.next + 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( risc_compiler ) + risc_compiler.reset_regs + #puts "adding risc #{risc.to_s}:#{risc.next.to_s}" + instruction = instruction.next + end + end + + end +end diff --git a/lib/mom/instruction/instruction.rb b/lib/mom/instruction.rb similarity index 52% rename from lib/mom/instruction/instruction.rb rename to lib/mom/instruction.rb index 0e4d5d21..c09ed54f 100644 --- a/lib/mom/instruction/instruction.rb +++ b/lib/mom/instruction.rb @@ -13,6 +13,17 @@ module Mom class Instruction include Util::List + def initialize( source , nekst = nil ) + @source = source + @next = nekst + return unless source + unless source.is_a?(String) or + source.is_a?(Vool::Statement) + raise "Source must be string or Instruction, not #{source.class}" + end + end + attr_reader :source + # to_risc, like the name says, converts the instruction to it's Risc equivalent. # The Risc machine is basically a simple register machine (kind of arm). # In other words Mom is the higher abstraction and so mom instructions convert @@ -27,18 +38,18 @@ module Mom end -require_relative "label" -require_relative "check" -require_relative "basic_values" -require_relative "simple_call" -require_relative "dynamic_call" -require_relative "block_yield" -require_relative "resolve_method" -require_relative "truth_check" -require_relative "not_same_check" -require_relative "jump" -require_relative "return_jump" -require_relative "slot_load" -require_relative "return_sequence" -require_relative "message_setup" -require_relative "argument_transfer" +require_relative "instruction/label" +require_relative "instruction/check" +require_relative "instruction/basic_values" +require_relative "instruction/simple_call" +require_relative "instruction/dynamic_call" +require_relative "instruction/block_yield" +require_relative "instruction/resolve_method" +require_relative "instruction/truth_check" +require_relative "instruction/not_same_check" +require_relative "instruction/jump" +require_relative "instruction/return_jump" +require_relative "instruction/slot_load" +require_relative "instruction/return_sequence" +require_relative "instruction/message_setup" +require_relative "instruction/argument_transfer" diff --git a/lib/mom/instruction/argument_transfer.rb b/lib/mom/instruction/argument_transfer.rb index 95fa19b7..c69c66bb 100644 --- a/lib/mom/instruction/argument_transfer.rb +++ b/lib/mom/instruction/argument_transfer.rb @@ -22,7 +22,8 @@ module Mom # receiver is a slot_definition # arguments is an array of SlotLoads - def initialize( receiver,arguments ) + def initialize( source , receiver,arguments ) + super(source) @receiver , @arguments = receiver , arguments raise "Receiver not SlotDefinition #{@receiver}" unless @receiver.is_a?(SlotDefinition) @arguments.each{|a| raise "args not SlotLoad #{a}" unless a.is_a?(SlotLoad)} @@ -35,7 +36,7 @@ module Mom # load receiver and then each arg into the new message # delegates to SlotLoad for receiver and to the actual args.to_risc def to_risc(compiler) - transfer = SlotLoad.new([:message , :next_message , :receiver] , @receiver, self).to_risc(compiler) + transfer = SlotLoad.new(self.source ,[:message , :next_message , :receiver] , @receiver, self).to_risc(compiler) compiler.reset_regs @arguments.each do |arg| arg.to_risc(compiler) diff --git a/lib/mom/instruction/block_yield.rb b/lib/mom/instruction/block_yield.rb index 873ab552..d0e7de30 100644 --- a/lib/mom/instruction/block_yield.rb +++ b/lib/mom/instruction/block_yield.rb @@ -6,7 +6,10 @@ module Mom class BlockYield < Instruction attr :arg_index - def initialize(index) + # pass in the source (vool statement) and the index. + # The index is the argument index of the block that we call + def initialize(source , index) + super(source) @arg_index = index end @@ -14,6 +17,7 @@ module Mom "BlockYield[#{arg_index}] " end + # almost as simple as a SimpleCall, use a dynamic_jump to get there def to_risc(compiler) return_label = Risc.label("block_yield", "continue_#{object_id}") index = arg_index diff --git a/lib/mom/instruction/label.rb b/lib/mom/instruction/label.rb index c0b202ef..8958a7e2 100644 --- a/lib/mom/instruction/label.rb +++ b/lib/mom/instruction/label.rb @@ -23,7 +23,8 @@ module Mom class Label < Instruction attr_reader :name - def initialize(name) + def initialize(source , name) + super(source) @name = name end @@ -32,9 +33,9 @@ module Mom end # generate the risc label lazily - def risc_label(comiler) + def risc_label(compiler) @risc_label ||= Risc.label(self,name) - comiler.add_constant(@risc_label.address) + compiler.add_constant(@risc_label.address) @risc_label end diff --git a/lib/mom/instruction/message_setup.rb b/lib/mom/instruction/message_setup.rb index cc8a2fef..01989063 100644 --- a/lib/mom/instruction/message_setup.rb +++ b/lib/mom/instruction/message_setup.rb @@ -22,6 +22,7 @@ module Mom attr_reader :method_source def initialize(method_source) + raise "no nil" unless method_source @method_source = method_source end diff --git a/lib/mom/instruction/resolve_method.rb b/lib/mom/instruction/resolve_method.rb index 63a1caeb..4698046b 100644 --- a/lib/mom/instruction/resolve_method.rb +++ b/lib/mom/instruction/resolve_method.rb @@ -15,7 +15,11 @@ module Mom class ResolveMethod < Instruction attr :cache_entry , :name - def initialize(name , cache_entry) + # pass in source (VoolStatement) + # name of the method (don't knwow the actaual method) + # and the cache_entry + def initialize(source , name , cache_entry) + super(source) @name = name @cache_entry = cache_entry end @@ -61,7 +65,7 @@ module Mom # temporary, need to raise really. factory! << Parfait.object_space.get_factory_for(:Integer) integer_tmp! << factory[:reserve] - Risc::Builtin::Object.emit_syscall( builder , :exit ) #uses integer_tmp + Mom::Builtin.emit_syscall( builder , :exit ) #uses integer_tmp add_code ok_label cache_entry[:cached_method] << callable_method diff --git a/lib/mom/instruction/return_jump.rb b/lib/mom/instruction/return_jump.rb index ceb1f6ae..2d9665d6 100644 --- a/lib/mom/instruction/return_jump.rb +++ b/lib/mom/instruction/return_jump.rb @@ -7,8 +7,20 @@ module Mom # class ReturnJump < Instruction + attr_reader :return_label + + # pass in the source_name (string/vool_instruction) for accounting purposes + # and the return_label, where we actually jump to. This is set up by the + # method_compiler, so it is easy to find (see return_label in compiler) + def initialize( source , label ) + super(source) + @return_label = label + end + + # the jump quite simple resolves to an uncondition risc Branch + # we use the label that is passed in at creation def to_risc(compiler) - compiler.add_code Risc::Branch.new(self , compiler.return_label) + compiler.add_code Risc::Branch.new(self , return_label.risc_label(compiler)) end end diff --git a/lib/mom/instruction/slot_load.rb b/lib/mom/instruction/slot_load.rb index 347459bb..90acd847 100644 --- a/lib/mom/instruction/slot_load.rb +++ b/lib/mom/instruction/slot_load.rb @@ -22,13 +22,14 @@ module Mom # SlotDefinition (see there) # # @right: A SlotDefinition with slots or a Mom::Constant - # original_source: optinally another mom instruction that wil be passed down to created + # original_source: optinally another mom instruction that will be passed down to created # risc instructions. (Because SlotLoad is often used internally in mom) class SlotLoad < Instruction attr_reader :left , :right , :original_source - def initialize(left , right, original_source = nil) + def initialize(source , left , right, original_source = nil) + super(source) @left , @right = left , right @left = SlotDefinition.new(@left.shift , @left) if @left.is_a? Array @right = SlotDefinition.new(@right.shift , @right) if @right.is_a? Array diff --git a/lib/mom/method_compiler.rb b/lib/mom/method_compiler.rb new file mode 100644 index 00000000..4b05663a --- /dev/null +++ b/lib/mom/method_compiler.rb @@ -0,0 +1,91 @@ +module Mom + + # MethodCompiler is used to generate Mom instructions for methods + # and to instantiate the methods correctly. + + class MethodCompiler < CallableCompiler + + 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 + def to_risc + risc_compiler = Risc::MethodCompiler.new(@callable , mom_instructions) + instructions_to_risc(risc_compiler) + block_compilers.each do |m_comp| + risc_compiler.block_compilers << m_comp.to_risc(@callable) + end + risc_compiler + end + + # 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 + + def add_method_to( target ) + target.add_method( @callable ) + end + + def create_block(arg_type , frame_type) + @callable.create_block(arg_type ,frame_type) + 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 + + # determine how given name need to be accsessed. + # For methods the options are args or frame + def slot_type_for(name) + if @callable.arguments_type.variable_index(name) + type = :arguments + else + type = :frame + end + [type , name] + end + + def add_block_compiler(compiler) + @block_compilers << compiler + 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 + + end +end diff --git a/lib/mom/mom.rb b/lib/mom/mom.rb index 2fec938e..22e0dbfb 100644 --- a/lib/mom/mom.rb +++ b/lib/mom/mom.rb @@ -12,7 +12,15 @@ # Machine capabilities (instructions) for basic operations. Use of macros for higher level. module Mom + # boot bubiltin function (subject to change) + def self.boot! + Builtin.boot_functions + end end -require_relative "instruction/instruction.rb" -require_relative "mom_compiler" +require_relative "instruction.rb" +require_relative "mom_collection" +require_relative "callable_compiler" +require_relative "method_compiler" +require_relative "block_compiler" +require_relative "builtin" diff --git a/lib/mom/mom_collection.rb b/lib/mom/mom_collection.rb new file mode 100644 index 00000000..cdb6df5f --- /dev/null +++ b/lib/mom/mom_collection.rb @@ -0,0 +1,47 @@ +module Mom + # The Compiler/Collection for the Mom level is a collection of Mom level Method + # compilers These will transform to Risc MethodCompilers on the way down. + # + # 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 MomCollection + attr_reader :method_compilers + + # Initialize with an array of risc MethodCompilers + def initialize(compilers = []) + @method_compilers = compilers + end + + # lazily instantiate the compilers for boot functions + # (in the hope of only booting the functions once) + def boot_compilers + @boot_compilers ||= Mom::Builtin.boot_functions + end + + # Return all compilers, namely the MethodCompilers passed in, plus the + # boot_function's compilers (boot_compilers) + def compilers + @method_compilers + boot_compilers + end + + # Append another MomCompilers method_compilers to this one. + def append(mom_compiler) + @method_compilers += mom_compiler.method_compilers + self + end + + def to_risc( ) + riscs = compilers.collect do | mom_c | + mom_c.to_risc + end + # 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 + + + end +end diff --git a/lib/parfait/block.rb b/lib/parfait/block.rb index dfcd8b7c..438246a1 100644 --- a/lib/parfait/block.rb +++ b/lib/parfait/block.rb @@ -3,10 +3,10 @@ module Parfait # A Block is a callable object, much like a CallableMethod. # Surprisingly similar in fact, as the block is really only missing the name. # - # The difference lies mostly in the way they are compiled + # The difference lies mostly in the way they are compiled (scope and return) # # Also both have a list of blocks defined in their scope. But this is - # notimplemented for blocks yet + # not implemented for blocks yet # class Block < Callable diff --git a/lib/parfait/type.rb b/lib/parfait/type.rb index b659c734..7f190a25 100644 --- a/lib/parfait/type.rb +++ b/lib/parfait/type.rb @@ -1,14 +1,15 @@ module Parfait -# An Object is really a hash like structure. It is dynamic and +# An Object is conceptually a hash like structure. It is dynamic and # you want to store values by name (instance variable names). # -# One could (like mri), store the names in each object, but that is wasteful in both time and space. -# Instead we store only the values, and access them by index. +# One could (like mri), store the names in each object, but that is wasteful in both +# time and space. +# Instead we store only the values, and access them by index (bit like c++). # The Type allows the mapping of names to index. -# The Type of an object describes the memory layout of the object. In a c analogy, it is the -# information defined in a struct. +# The Type of an object describes the memory layout of the object. In a c analogy, +# it is the information defined in a struct. # The Type is a list of the names of instance variables, and their value types (int etc). # # Every object has a Type to describe it, so it's *first* instance variable is **always** @@ -21,14 +22,13 @@ module Parfait # But Objects must also be able to carry methods themselves (ruby calls singleton_methods) # and those too are stored in the Type (both type and class include behaviour) -# The object is an List of values of length n - -# The Type is a list of n names and n types that describe the values stored in an actual object. - +# The object is an "List" (memory location) of values of length n +# The Type is a list of n names and n types that describe the values stored in an +# actual object. # Together they turn the object into a hash like structure -# For types to be a useful concept, they have to be unique and immutable. Any "change", like adding -# a name/type pair, will result in a new instance. +# For types to be a useful concept, they have to be unique and immutable. Any "change", +# like adding a name/type pair, will result in a new type instance. # The Type class carries a hash of types of the systems, which is used to ensure that # there is only one instance of every type. Hash and equality are defined on type diff --git a/lib/parfait/vool_method.rb b/lib/parfait/vool_method.rb index 8e3ff8be..603f0273 100644 --- a/lib/parfait/vool_method.rb +++ b/lib/parfait/vool_method.rb @@ -5,7 +5,7 @@ module Parfait # Type objects are already created for args and locals, but the main attribute # is the source, which is a Vool::Statement # - # Classes store VoolMethods, while Types store CallableMethod + # Classes store VoolMethods, while Types store Risc::CallableMethod # A Type referes to a Class , but a Class (interface) is implemented by many types # as it changes during the course of it's life. Types do not change. Objects have # type, and so only indirectly a class. @@ -14,7 +14,7 @@ module Parfait attr :type, :name , :args_type , :frame_type attr_reader :source - + def initialize(name , args_type , frame_type , source ) self.name = name self.args_type = args_type @@ -34,9 +34,9 @@ module Parfait def compiler_for(self_type) callable_method = create_callable_method(self_type) - compiler = Risc::MethodCompiler.new( callable_method ) + compiler = Mom::MethodCompiler.new( callable_method ) head = @source.to_mom( compiler ) - compiler.add_mom(head) + compiler.add_code(head) compiler end end diff --git a/lib/risc.rb b/lib/risc.rb index 7dcb872c..65ab5c54 100644 --- a/lib/risc.rb +++ b/lib/risc.rb @@ -12,15 +12,11 @@ class Class end end -# The Risc Machine, is an abstract machine with registers. Think of it as an arm machine with -# normal instruction names. It is not however an abstraction of existing hardware, but only -# of that subset that we need. # See risc/Readme module Risc # module method to reset, and init def self.boot! Position.clear_positions - Builtin.boot_functions end end @@ -35,6 +31,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? @@ -46,5 +43,4 @@ end require_relative "risc/instruction" require_relative "risc/register_value" require_relative "risc/text_writer" -require_relative "risc/builtin" require_relative "risc/builder" diff --git a/lib/risc/block_compiler.rb b/lib/risc/block_compiler.rb index 73eef675..5ad409b9 100644 --- a/lib/risc/block_compiler.rb +++ b/lib/risc/block_compiler.rb @@ -4,16 +4,15 @@ module Risc # class BlockCompiler < CallableCompiler - attr_reader :block , :risc_instructions , :constants - alias :block :callable + attr_reader :block , :risc_instructions , :constants , :in_method - def initialize( block , method) - @method = method - super(block) + def initialize( block , in_method , mom_label) + @in_method = in_method + super(block , mom_label) end def source_name - "#{@method.self_type.name}.init" + "#{@in_method.self_type.name}.init" end # resolve the type of the slot, by inferring from it's name, using the type @@ -24,9 +23,9 @@ module Risc def slot_type( slot , type) new_type = super if slot == :caller - extra_info = { type_frame: @method.frame_type , - type_arguments: @method.arguments_type , - type_self: @method.self_type} + extra_info = { type_frame: @in_method.frame_type , + type_arguments: @in_method.arguments_type , + type_self: @in_method.self_type} end return new_type , extra_info end @@ -38,9 +37,9 @@ module Risc slot_def = [:arguments] elsif @callable.frame_type.variable_index(name) slot_def = [:frame] - elsif @method.arguments_type.variable_index(name) + elsif @in_method.arguments_type.variable_index(name) slot_def = [:caller , :caller ,:arguments ] - elsif @method.frame_type.variable_index(name) + elsif @in_method.frame_type.variable_index(name) slot_def = [:caller ,:caller , :frame ] elsif raise "no variable #{name} , need to resolve at runtime" diff --git a/lib/risc/builder.rb b/lib/risc/builder.rb index aae83391..45726432 100644 --- a/lib/risc/builder.rb +++ b/lib/risc/builder.rb @@ -4,6 +4,12 @@ module Risc # # The code is added to the method_compiler. # + # Basically this allows to many Risc instructions with extremely readable code. + # example: + # space << Parfait.object_space # load constant + # message[:receiver] << space #make current message's (r0) receiver the space + # See http://ruby-x.org/rubyx/builder.html for details + # class Builder attr_reader :built , :compiler diff --git a/lib/risc/builtin/compile_helper.rb b/lib/risc/builtin/compile_helper.rb deleted file mode 100644 index 43a2b93d..00000000 --- a/lib/risc/builtin/compile_helper.rb +++ /dev/null @@ -1,14 +0,0 @@ - -module Risc - module Builtin - module CompileHelper - - def compiler_for( clazz_name , method_name , arguments , locals = {}) - frame = Parfait::NamedList.type_for( locals ) - args = Parfait::NamedList.type_for( arguments ) - MethodCompiler.compiler_for_class(clazz_name , method_name , args, frame ) - end - - end - end -end diff --git a/lib/risc/builtin/integer.rb b/lib/risc/builtin/integer.rb deleted file mode 100644 index eba3fc37..00000000 --- a/lib/risc/builtin/integer.rb +++ /dev/null @@ -1,183 +0,0 @@ -module Risc - module Builtin - # integer related kernel functions - # all these functions (return the function they implement) assume interger input - # Also the returned integer object has to be passed in to avoid having to allocate it. - # - # This means the methods will have to be renamed at some point and wrapped - module Integer - module ClassMethods - include CompileHelper - - # div by 4, ie shift right by 2 - # Mostly created for testing at this point, as it is short - # return new int with result - def div4(context) - compiler = compiler_for(:Integer,:div4 ,{}) - builder = compiler.builder(compiler.source) - integer_tmp = builder.allocate_int - builder.build do - integer_self! << message[:receiver] - integer_self.reduce_int - integer_1! << 2 - integer_self.op :>> , integer_1 - integer_tmp[Parfait::Integer.integer_index] << integer_self - message[:return_value] << integer_tmp - end - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - # implemented by the comparison - def >( context ) - comparison( :> ) - end - # implemented by the comparison - def <( context ) - comparison( :< ) - end - # implemented by the comparison - def <=( context ) - comparison( :<= ) - end - # implemented by the comparison - def >=( context ) - comparison( :>= ) - end - - # all (four) comparison operation are quite similar and implemented here - # - reduce the ints (assume int as input) - # - subtract the fixnums - # - check for minus ( < and > ) - # - also check for zero (<= and >=) - # - load true or false object into return, depending on check - # - return - def comparison( operator ) - compiler = compiler_for(:Integer, operator ,{other: :Integer }) - builder = compiler.builder(compiler.source) - builder.build do - integer! << message[:receiver] - integer.reduce_int - integer_reg! << message[:arguments] - integer_reg << integer_reg[Parfait::NamedList.type_length + 0] #"other" is at index 0 - integer_reg.reduce_int - swap_names(:integer , :integer_reg) if(operator.to_s.start_with?('<') ) - integer.op :- , integer_reg - if_minus false_label - if_zero( false_label ) if operator.to_s.length == 1 - object! << Parfait.object_space.true_object - branch merge_label - add_code false_label - object << Parfait.object_space.false_object - add_code merge_label - message[:return_value] << object - end - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - - # not implemented, would need a itos and that needs "new" (wip) - def putint(context) - compiler = compiler_for(:Integer,:putint ,{}) - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - - # implemented all known binary operators that map straight to machine codes - # this function (similar to comparison): - # - unpacks the intergers to fixnum - # - applies the operator (at a risc level) - # - gets a new integer and stores the result - # - returns the new int - def operator_method( op_sym ) - compiler = compiler_for(:Integer, op_sym ,{other: :Integer }) - builder = compiler.builder(compiler.source) - integer_tmp = builder.allocate_int - builder.build do - integer! << message[:receiver] - integer.reduce_int - integer_reg! << message[:arguments] - integer_reg << integer_reg[Parfait::NamedList.type_length + 0] #"other" is at index 0 - integer_reg.reduce_int - integer.op op_sym , integer_reg - integer_tmp[Parfait::Integer.integer_index] << integer - message[:return_value] << integer_tmp - end - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - - # as the name suggests, this devides the integer (self) by ten - # - # This version is lifted from some arm assembler tricks and is _much_ - # faster than the general div versions. I think it was about three - # times less instructions. Useful for itos - # - # In fact it is possible to generate specific div function for any given - # integer and some are even more faster (as eg div4). - def div10( context ) - s = "div_10 " - compiler = compiler_for(:Integer,:div10 ,{}) - builder = compiler.builder(compiler.source) - integer_tmp = builder.allocate_int - builder.build do - integer_self! << message[:receiver] - integer_self.reduce_int - integer_1! << integer_self - integer_reg! << integer_self - - integer_const! << 1 - integer_1.op :>> , integer_const - - integer_const << 2 - integer_reg.op :>> , integer_const - integer_reg.op :+ , integer_1 - - integer_const << 4 - integer_1 << integer_reg - integer_reg.op :>> , integer_1 - - integer_reg.op :+ , integer_1 - - integer_const << 8 - integer_1 << integer_reg - integer_1.op :>> , integer_const - - integer_reg.op :+ , integer_1 - - integer_const << 16 - integer_1 << integer_reg - integer_1.op :>> , integer_const - - integer_reg.op :+ , integer_1 - - integer_const << 3 - integer_reg.op :>> , integer_const - - integer_const << 10 - integer_1 << integer_reg - integer_1.op :* , integer_const - - integer_self.op :- , integer_1 - integer_1 << integer_self - - integer_const << 6 - integer_1.op :+ , integer_const - - integer_const << 4 - integer_1.op :>> , integer_const - - integer_reg.op :+ , integer_1 - - integer_tmp[Parfait::Integer.integer_index] << integer_reg - message[:return_value] << integer_tmp - - end - - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - end - extend ClassMethods - end - end -end diff --git a/lib/risc/builtin/object.rb b/lib/risc/builtin/object.rb deleted file mode 100644 index c55909eb..00000000 --- a/lib/risc/builtin/object.rb +++ /dev/null @@ -1,148 +0,0 @@ -module Risc - module Builtin - class Object - module ClassMethods - include CompileHelper - - # self[index] basically. Index is the first arg - # return is stored in return_value - def get_internal_word( context ) - compiler = compiler_for(:Object , :get_internal_word ,{at: :Integer}) - compiler.builder(compiler.source).build do - object! << message[:receiver] - integer! << message[:arguments] - integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 - integer.reduce_int - object << object[integer] - message[:return_value] << object - end - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - - # self[index] = val basically. Index is the first arg , value the second - # return the value passed in - def set_internal_word( context ) - compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, value: :Object} ) - compiler.builder(compiler.source).build do - object! << message[:receiver] - integer! << message[:arguments] - object_reg! << integer[Parfait::NamedList.type_length + 1] #"value" is at index 1 - integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 - integer.reduce_int - object[integer] << object_reg - message[:return_value] << object_reg - end - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - - # every object needs a method missing. - # Even if it's just this one, sys_exit (later raise) - def _method_missing( context ) - compiler = compiler_for(:Object,:method_missing ,{}) - builder = compiler.builder(compiler.source) - builder.prepare_int_return # makes integer_tmp variable as return - emit_syscall( builder , :exit ) - return compiler - end - - # this is the really really first place the machine starts (apart from the jump here) - # it isn't really a function, ie it is jumped to (not called), exits and may not return - # so it is responsible for initial setup: - # - load fist message, set up Space as receiver - # - call main, ie set up message for that etc - # - exit (exit_sequence) which passes a machine int out to c - def __init__( context ) - compiler = MethodCompiler.compiler_for_class(:Object,:__init__ , - Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({})) - builder = compiler.builder(compiler.source) - builder.build do - factory! << Parfait.object_space.get_factory_for(:Message) - message << factory[:next_object] - next_message! << message[:next_message] - factory[:next_object] << next_message - end - - Mom::MessageSetup.new(Parfait.object_space.get_main).build_with( builder ) - - builder.build do - message << message[:next_message] - space? << Parfait.object_space - message[:receiver] << space - end - - exit_label = Risc.label(compiler.source , "#{compiler.receiver_type.object_class.name}.#{compiler.source.name}" ) - ret_tmp = compiler.use_reg(:Label).set_builder(builder) - builder.build do - ret_tmp << exit_label - message[:return_address] << ret_tmp - add_code Risc.function_call( "__init__ issue call" , Parfait.object_space.get_main) - add_code exit_label - end - compiler.reset_regs - exit_sequence(builder) - return compiler - end - - # the exit function - # mainly calls exit_sequence - def exit( context ) - compiler = compiler_for(:Object,:exit ,{}) - builder = compiler.builder(compiler.source) - builder.prepare_int_return # makes integer_tmp variable as return - exit_sequence(builder) - return compiler - end - - # a sort of inline version of exit method. - # Used by exit and __init__ (so it doesn't have to call it) - # Assumes int return value and extracts the fixnum for process exit code - def exit_sequence(builder) - save_message( builder ) - builder.build do - message << message[:return_value] - message.reduce_int - add_code Syscall.new("emit_syscall(exit)", :exit ) - end - end - - # emit the syscall with given name - # there is a Syscall instruction, but the message has to be saved and restored - def emit_syscall( builder , name ) - save_message( builder ) - builder.add_code Syscall.new("emit_syscall(#{name})", name ) - restore_message(builder) - return unless (@clazz and @method) - builder.add_code Risc.label( "#{@clazz.name}.#{@message.name}" , "return_syscall" ) - end - - # save the current message, as the syscall destroys all context - # - # This relies on linux to save and restore all registers - # - def save_message(builder) - r8 = RegisterValue.new( :r8 , :Message).set_builder(builder) - builder.build {r8 << message} - end - - # restore the message that we save in r8 - # before th restore, the syscall return, a fixnum, is saved - # The caller of this method is assumed to caal prepare_int_return - # so that the return value already has an integer instance - # This instance is filled with os return value - def restore_message(builder) - r8 = RegisterValue.new( :r8 , :Message) - builder.build do - integer_reg! << message - message << r8 - integer_2! << message[:return_value] - integer_2[Parfait::Integer.integer_index] << integer_reg - end - end - - end - extend ClassMethods - end - end -end diff --git a/lib/risc/builtin/word.rb b/lib/risc/builtin/word.rb deleted file mode 100644 index d67d72ef..00000000 --- a/lib/risc/builtin/word.rb +++ /dev/null @@ -1,70 +0,0 @@ -module Risc - module Builtin - module Word - module ClassMethods - include CompileHelper - - # wrapper for the syscall - # io/file currently hardcoded to stdout - # set up registers for syscall, ie - # - pointer in r1 - # - length in r2 - # - emit_syscall (which does the return of an integer, see there) - def putstring( context) - compiler = compiler_for(:Word , :putstring ,{}) - builder = compiler.builder(compiler.source) - builder.prepare_int_return # makes integer_tmp variable as return - builder.build do - word! << message[:receiver] - integer! << word[Parfait::Word.get_length_index] - end - Risc::Builtin::Object.emit_syscall( builder , :putstring ) - compiler.add_mom( Mom::ReturnSequence.new) - compiler - end - - # self[index] basically. Index is the first arg > 0 - # return a word sized new int, in return_value - # - # Note: no index (or type) checking. Method should be internal and check before. - # Which means the returned integer could be passed in, instead of allocated. - def get_internal_byte( context) - compiler = compiler_for(:Word , :get_internal_byte , {at: :Integer}) - builder = compiler.builder(compiler.source) - integer_tmp = builder.allocate_int - builder.build do - object! << message[:receiver] - integer! << message[:arguments] - integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 - integer.reduce_int - object <= object[integer] - integer_tmp[Parfait::Integer.integer_index] << object - message[:return_value] << integer_tmp - end - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - - # self[index] = val basically. Index is the first arg ( >0 , unchecked), - # value the second, which is also returned - def set_internal_byte( context ) - compiler = compiler_for(:Word, :set_internal_byte , {at: :Integer , value: :Integer} ) - compiler.builder(compiler.source).build do - word! << message[:receiver] - integer! << message[:arguments] - integer_reg! << integer[Parfait::NamedList.type_length + 1] #"value" is at index 1 - message[:return_value] << integer_reg - integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 - integer.reduce_int - integer_reg.reduce_int - word[integer] <= integer_reg - end - compiler.add_mom( Mom::ReturnSequence.new) - return compiler - end - - end - extend ClassMethods - end - end -end diff --git a/lib/risc/callable_compiler.rb b/lib/risc/callable_compiler.rb index 8a138d06..85b0aef9 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) + # Also start instuction, usually a label is mandatory + def initialize( callable , mom_label) @callable = callable @regs = [] @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 = mom_label.risc_label(self) reset_regs end attr_reader :risc_instructions , :constants , :block_compilers , :callable , :current @@ -32,20 +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) raise "Must be Parfait #{const}" unless const.is_a?(Parfait::Object) diff --git a/lib/risc/method_compiler.rb b/lib/risc/method_compiler.rb index 4a986759..936175f8 100644 --- a/lib/risc/method_compiler.rb +++ b/lib/risc/method_compiler.rb @@ -1,13 +1,14 @@ module Risc - # MethodCompiler (old name) is used to generate risc instructions for methods - # and to instantiate the methods correctly. Most of the init is typed layer stuff, - # but there is some logic too. + # MethodCompiler is used to generate risc instructions for methods + # and to instantiate the methods correctly. class MethodCompiler < CallableCompiler - def initialize( method ) - super(method) + # Methods starts with a Label, both in risc and mom. + # Pass in the callable(method) and the mom label that the method starts with + def initialize( method , mom_label) + super(method , mom_label) end #include block_compilers constants @@ -33,7 +34,7 @@ module Risc # # return compiler_for_type with the resolved type # - def self.compiler_for_class( class_name , method_name , args , frame ) + def self.compiler_for_clazz( 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) @@ -52,7 +53,7 @@ module Risc # 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) + def self.compiler_for_typez( 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 diff --git a/lib/risc/position/position.rb b/lib/risc/position/position.rb index e3159454..d3c4e915 100644 --- a/lib/risc/position/position.rb +++ b/lib/risc/position/position.rb @@ -186,7 +186,7 @@ module Risc # populate the position caches (forward and revese) with the given position # forward caches object -> position # reverse caches position.at > position - # Labels do not participatein reverse cache + # Labels do not participate in reverse cache def self.set_cache( position , to) postest = Position.positions[position.object] unless to < 0 raise "Mismatch #{position}" if postest and postest != position diff --git a/lib/mom/mom_compiler.rb b/lib/risc/risc_collection.rb similarity index 66% rename from lib/mom/mom_compiler.rb rename to lib/risc/risc_collection.rb index 8f4020f3..bc3c024b 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 @@ -18,21 +10,9 @@ module Mom @method_compilers = compilers end - # lazily instantiate the compilers for boot functions - # (in the hope of only booting the functions once) - def boot_compilers - @boot_compilers ||= Risc::Builtin.boot_functions - end - - # Return all compilers, namely the MethodCompilers passed in, plus the - # boot_function's compilers (boot_compilers) - def compilers - @method_compilers + boot_compilers - end - # collects constants from all compilers into one array def constants - compilers.inject([]){|sum ,comp| sum + comp.constants } + method_compilers.inject([]){|sum ,comp| sum + comp.constants } end # Append another MomCompilers method_compilers to this one. @@ -55,7 +35,7 @@ module Mom # go through all methods and translate them to cpu, given the translator def translate_methods(translator) - compilers.collect do |compiler| + method_compilers.collect do |compiler| #log.debug "Translate method #{compiler.method.name}" translate_method(compiler , translator) end.flatten diff --git a/lib/ruby/README.md b/lib/ruby/README.md new file mode 100644 index 00000000..dc4ef9a0 --- /dev/null +++ b/lib/ruby/README.md @@ -0,0 +1,31 @@ +# Ruby + +A representation of the ruby code. + +## Concrete Syntax tree + +Ruby is parsed by the parser gem (big thanks to whitequark). Own attempts at +this task have failed utterly, because ruby is a _huge_ language (and not well +defined at that) + +Alas, the parser gem creates an abstract syntax tree, meaning one class is used +to represent all node types. + +Imho object oriented languages have a class system to do just that, ie represent +what we may loosely call type here, ie the kind of statement. + +The ruby layer is really all about defining classes for every kind of statement, +thus "typing" the syntax tree, and making it concrete. + +## to Vool + +In our nice layers, we are ont the way down to Vool, a simplified version of oo. + +It has proven handy to have this layer, so the code for transforming each object +is in the class representing that object. (As one does in oo, again imho). + +## Parfait objects + +The compilation process ends up creating (parfait) objects to represent +things like classes, types and constants. This is not done here yet, but in +the vool layer. diff --git a/lib/rubyx.rb b/lib/rubyx.rb index 62cf4f0e..1e849175 100644 --- a/lib/rubyx.rb +++ b/lib/rubyx.rb @@ -1,11 +1,12 @@ require "rx-file" require "util/logging" +require "util/list" require_relative "elf/object_writer" require_relative "risc" +require_relative "mom/mom" require_relative "arm/arm_machine" require_relative "arm/arm_platform" require_relative "vool/statement" require_relative "ruby" require_relative "rubyx/rubyx_compiler" -require_relative "mom/mom" diff --git a/lib/rubyx/rubyx_compiler.rb b/lib/rubyx/rubyx_compiler.rb index 2dd83cde..b10f710f 100644 --- a/lib/rubyx/rubyx_compiler.rb +++ b/lib/rubyx/rubyx_compiler.rb @@ -1,5 +1,14 @@ module RubyX - # The RubyXCompiler provides the main interface to create binaries + # The RubyXCompiler provides the main interface to create binaries, and also + # give helper functions to create any intermediate layer. + # Layers are: + # - ruby , always needed as input, string + # - vool - intermediate language layer + # - mom - intermediate machine layer + # - risc - "last" intermediate machine layer + # - target - arm or interpreter binary code + # - binary - "linked" code, everything need to create an elf binary + # # # There are methods to go from ruby to any of the layers in the system # (mainly for testing). ruby_to_binary creates actual binary code @@ -21,6 +30,7 @@ module RubyX # initialize boots Parfait and Risc (ie load Builin) def initialize(options) Parfait.boot!(options[:parfait] || {}) + Mom.boot! Risc.boot! end @@ -37,42 +47,58 @@ module RubyX to_binary(platform) end + # ruby_to_target creates Target instructions (but does not link) + # + # After creating vool, we call to_target + # Return a Linker + def ruby_to_target(ruby , platform) + ruby_to_vool(ruby) + to_target( platform ) + end + + # ruby_to_risc creates Risc instructions + # + # After creating vool, we call to_risc + # Return a RiscCollection + def ruby_to_risc(ruby) + ruby_to_vool(ruby) + to_risc() + end + + # Transform the incoming ruby source (string) to mom + # + # The vool is stored using ruby_to_vool,the to_mom is called + # Return Mom Statement + def ruby_to_mom(ruby) + ruby_to_vool(ruby) + to_mom + end + # Process previously stored vool source to binary. - # Binary code is generated byu calling to_risc, then positioning and calling + # Binary code is generated by calling to_risc, then positioning and calling # create_binary on the linker. The linker may then be used to creat a binary file. # The biary the method name refers to is binary code in memory, or in BinaryCode # objects to be precise. def to_binary(platform) - linker = to_risc(platform) + linker = to_target(platform) linker.position_all linker.create_binary linker end - # ruby_to_risc creates Risc instructions (as the name implies), but also - # translates those to the platform given - # - # After creating vool, we call to_risc - def ruby_to_risc(ruby, platform) - ruby_to_vool(ruby) - to_risc(platform) + # transform stored vool to target code + # return a linker + def to_target(platform) + raise "No platform given" unless platform + collection = to_risc + collection.translate(platform) end - # Process previously stored vool source. First to mom, then to platform. - # Translating to platform returns a linker that is returned and can be used - # to generate binaries - def to_risc(platform) + # Process previously stored vool source to risc. + # return a Risc::RiscCollection , a collection of MethodCompilers + def to_risc() mom = to_mom - mom.translate(platform) - end - - # ruby_to_mom does exactly that, it transform the incoming ruby source (string) - # to mom - # The vool is stored using ruby_to_vool, and if there was previous source, - # this will also be momed - def ruby_to_mom(ruby) - ruby_to_vool(ruby) - to_mom + mom.to_risc() end # return mom for the previously stored vool source. @@ -108,9 +134,7 @@ module RubyX compiler = RubyXCompiler.new(options) compiler.load_parfait if options[:load_parfait] compiler.ruby_to_vool(ruby) - platform = options[:platform] - raise "No platform given" unless platform - compiler.to_binary(platform) + compiler.to_binary(options[:platform]) end end end diff --git a/lib/vool/README.md b/lib/vool/README.md index 64f153d6..2c5e8982 100644 --- a/lib/vool/README.md +++ b/lib/vool/README.md @@ -9,16 +9,14 @@ Possibly later other languages can compile to this level and use rx-file as code ## Syntax tree -Vool is the layer of concrete syntax tree. The Parser gem is used to parse ruby. It creates -an abstract syntax tree which is then transformed. +Vool is a layer with concrete syntax tree, just like the ruby layer above. +Vool is just simplified, without fluff, see below. -The next layer down is the Mom, Minimal object Machine, which uses an instruction tree. -That is on the way down we create instructions, but stays in tree format. Only the next step -down to the Risc layer moves to an instruction stream. +The next layer down is the Mom, Minimal object Machine, which uses an instruction list. -The nodes of the syntax tree are all the things one would expect from a language, if statements -and the like. There is no context yet, and actual objects, representing classes and -methods, will be created on the way down. +The nodes of the syntax tree are all the things one would expect from a language, +if statements and the like. There is no context yet, and actual objects, +representing classes and methods, will be created on the way down. ## Fluff @@ -30,3 +28,9 @@ existence of until, which really means if not. Other examples, some more impactf - no case - no elseif (no unless, no ternary operator) - no global variables. + +## Parfait objects + +The compilation process ends up creating (parfait) objects to represent +things like classes, types and constants. This is done in this layer, +on the way down to MOM (ie not during init) diff --git a/lib/vool/assignment.rb b/lib/vool/assignment.rb index 0c29b35d..e5838e0f 100644 --- a/lib/vool/assignment.rb +++ b/lib/vool/assignment.rb @@ -3,6 +3,8 @@ module Vool class Assignment < Statement attr_reader :name , :value def initialize(name , value ) + raise "Name nil #{self}" unless name + raise "Value nil #{self}" unless value @name , @value = name , value end diff --git a/lib/vool/block_statement.rb b/lib/vool/block_statement.rb index e1f25321..d2ea16f6 100644 --- a/lib/vool/block_statement.rb +++ b/lib/vool/block_statement.rb @@ -21,9 +21,9 @@ module Vool # to the method compiler for further processing def to_mom( compiler ) parfait_block = self.parfait_block(compiler) - block_compiler = Risc::BlockCompiler.new( parfait_block , compiler.get_method ) + block_compiler = Mom::BlockCompiler.new( parfait_block , compiler.get_method ) head = body.to_mom( block_compiler ) - block_compiler.add_mom(head) + block_compiler.add_code(head) block_compiler end diff --git a/lib/vool/class_method_statement.rb b/lib/vool/class_method_statement.rb index 916d6989..076dacd4 100644 --- a/lib/vool/class_method_statement.rb +++ b/lib/vool/class_method_statement.rb @@ -11,6 +11,7 @@ module Vool raise "not meta" unless clazz.class == Parfait::MetaClass raise( "no class in #{self}") unless clazz method = clazz.add_method_for(name , make_arg_type , make_frame , body ) +#VoolMethod compiler = method.compiler_for(clazz.instance_type) each {|node| raise "Blocks not implemented" if node.is_a?(BlockStatement)} compiler diff --git a/lib/vool/class_statement.rb b/lib/vool/class_statement.rb index 2b768840..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| @@ -29,7 +42,7 @@ module Vool raise "Only methods for now #{node.class}:#{node}" end end - Mom::MomCompiler.new(method_compilers) + Mom::MomCollection.new(method_compilers) end def each(&block) @@ -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/if_statement.rb b/lib/vool/if_statement.rb index 4bd8f1a3..3e4b26b8 100644 --- a/lib/vool/if_statement.rb +++ b/lib/vool/if_statement.rb @@ -15,8 +15,8 @@ module Vool end def simple_if(compiler) - true_label = Mom::Label.new( "true_label_#{object_id.to_s(16)}") - merge_label = Mom::Label.new( "merge_label_#{object_id.to_s(16)}") + true_label = Mom::Label.new( self,"true_label_#{object_id.to_s(16)}") + merge_label = Mom::Label.new( self,"merge_label_#{object_id.to_s(16)}") head = Mom::TruthCheck.new(condition.slot_definition(compiler) , merge_label) head << true_label @@ -25,9 +25,9 @@ module Vool end def full_if(compiler) - true_label = Mom::Label.new( "true_label_#{object_id.to_s(16)}") - false_label = Mom::Label.new( "false_label_#{object_id.to_s(16)}") - merge_label = Mom::Label.new( "merge_label_#{object_id.to_s(16)}") + true_label = Mom::Label.new( self , "true_label_#{object_id.to_s(16)}") + false_label = Mom::Label.new( self , "false_label_#{object_id.to_s(16)}") + merge_label = Mom::Label.new( self , "merge_label_#{object_id.to_s(16)}") head = Mom::TruthCheck.new(condition.slot_definition(compiler) , false_label) head << true_label diff --git a/lib/vool/ivar_assignment.rb b/lib/vool/ivar_assignment.rb index da9da94a..1f70f5bc 100644 --- a/lib/vool/ivar_assignment.rb +++ b/lib/vool/ivar_assignment.rb @@ -5,7 +5,7 @@ module Vool def to_mom( compiler ) to = Mom::SlotDefinition.new(:message ,[ :receiver , @name]) from = @value.slot_definition(compiler) - return chain_assign( Mom::SlotLoad.new(to,from) , compiler) + return chain_assign( Mom::SlotLoad.new(self,to,from) , compiler) end end diff --git a/lib/vool/local_assignment.rb b/lib/vool/local_assignment.rb index c8f423d3..97d0e979 100644 --- a/lib/vool/local_assignment.rb +++ b/lib/vool/local_assignment.rb @@ -6,9 +6,9 @@ module Vool slot_def = compiler.slot_type_for(@name) to = Mom::SlotDefinition.new(:message ,slot_def) from = @value.slot_definition(compiler) - return chain_assign( Mom::SlotLoad.new(to,from) , compiler) + return chain_assign( Mom::SlotLoad.new(self,to,from) , compiler) end - + 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/lib/vool/return_statement.rb b/lib/vool/return_statement.rb index 35c3d879..ae4d5928 100644 --- a/lib/vool/return_statement.rb +++ b/lib/vool/return_statement.rb @@ -16,9 +16,9 @@ module Vool # - store the given return value, this is a SlotMove # - activate return sequence (reinstantiate old message and jump to return address) def to_mom( compiler ) - ret = Mom::SlotLoad.new( [:message , :return_value] , + ret = Mom::SlotLoad.new( self , [:message , :return_value] , @return_value.slot_definition(compiler) ) - ret << Mom::ReturnJump.new + ret << Mom::ReturnJump.new(self , compiler.return_label ) end def to_s(depth = 0) diff --git a/lib/vool/send_statement.rb b/lib/vool/send_statement.rb index e0336fd6..c19bd555 100644 --- a/lib/vool/send_statement.rb +++ b/lib/vool/send_statement.rb @@ -50,9 +50,9 @@ module Vool arg_target = [:message , :next_message , :arguments] args = [] @arguments.each_with_index do |arg , index| # +1 because of type - args << Mom::SlotLoad.new( arg_target + [index + 1] , arg.slot_definition(compiler)) + args << Mom::SlotLoad.new(self, arg_target + [index + 1] , arg.slot_definition(compiler)) end - setup << Mom::ArgumentTransfer.new( mom_receive , args ) + setup << Mom::ArgumentTransfer.new(self, mom_receive , args ) end def simple_call(compiler) @@ -73,10 +73,10 @@ module Vool # if not, change and find method for the type (simple_call to resolve_method) # conceptually easy in ruby, but we have to compile that "easy" ruby def cache_check(compiler) - ok = Mom::Label.new("cache_ok_#{self.object_id}") + ok = Mom::Label.new(self,"cache_ok_#{self.object_id}") check = build_condition(ok, compiler) # if cached_type != current_type - check << Mom::SlotLoad.new([dynamic_call.cache_entry, :cached_type] , receiver_type_definition(compiler)) - check << Mom::ResolveMethod.new( @name , dynamic_call.cache_entry ) + check << Mom::SlotLoad.new(self,[dynamic_call.cache_entry, :cached_type] , receiver_type_definition(compiler)) + check << Mom::ResolveMethod.new(self, @name , dynamic_call.cache_entry ) check << ok end diff --git a/lib/vool/while_statement.rb b/lib/vool/while_statement.rb index aa388df4..b85f1768 100644 --- a/lib/vool/while_statement.rb +++ b/lib/vool/while_statement.rb @@ -10,8 +10,8 @@ module Vool end def to_mom( compiler ) - merge_label = Mom::Label.new( "merge_label_#{object_id.to_s(16)}") - cond_label = Mom::Label.new( "cond_label_#{object_id.to_s(16)}") + merge_label = Mom::Label.new(self, "merge_label_#{object_id.to_s(16)}") + cond_label = Mom::Label.new(self, "cond_label_#{object_id.to_s(16)}") codes = cond_label codes << @hoisted.to_mom(compiler) if @hoisted codes << Mom::TruthCheck.new(condition.slot_definition(compiler) , merge_label) diff --git a/lib/vool/yield_statement.rb b/lib/vool/yield_statement.rb index a218bfc3..0170318c 100644 --- a/lib/vool/yield_statement.rb +++ b/lib/vool/yield_statement.rb @@ -33,13 +33,13 @@ module Vool # this needs run-time variable resolution, which is just not done. # we brace ourselves with the check, and exit (later raise) if . . . def method_check(compiler) - ok_label = Mom::Label.new("method_ok_#{self.object_id}") + ok_label = Mom::Label.new(self,"method_ok_#{self.object_id}") compile_method = Mom::SlotDefinition.new( compiler.get_method , []) runtime_method = Mom::SlotDefinition.new( :message , [ :method] ) check = Mom::NotSameCheck.new(compile_method , runtime_method, ok_label) # TODO? Maybe create mom instructions for this #builder = compiler.builder("yield") - #Risc::Builtin::Object.exit_sequence(builder) + #Risc::Builtin.exit_sequence(builder) #check << builder.built check << ok_label end @@ -53,10 +53,10 @@ module Vool arg_target = [:message , :next_message , :arguments] args = [] @arguments.each_with_index do |arg , index| # +1 because of type - args << Mom::SlotLoad.new( arg_target + [index + 1] , arg.slot_definition(compiler)) + args << Mom::SlotLoad.new(self, arg_target + [index + 1] , arg.slot_definition(compiler)) end - setup << Mom::ArgumentTransfer.new( mom_receive , args ) - setup << Mom::BlockYield.new( arg_index ) + setup << Mom::ArgumentTransfer.new( self , mom_receive , args ) + setup << Mom::BlockYield.new( self , arg_index ) end end diff --git a/test/elf/test_zero.rb b/test/elf/test_zero.rb index c6c006ca..bb5aa800 100644 --- a/test/elf/test_zero.rb +++ b/test/elf/test_zero.rb @@ -6,9 +6,7 @@ module Elf def setup super - @linker = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_risc(as_main("return 1"),:arm) - @linker.position_all - @linker.create_binary + @linker = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_binary(as_main("return 1"),:arm) end def test_empty_translate diff --git a/test/helper.rb b/test/helper.rb index 86116324..2e886af7 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -14,7 +14,7 @@ end require "minitest/color" require "minitest/autorun" -require "minitest/fail_fast" unless ENV["TEST_ALL"] +#require "minitest/fail_fast" unless ENV["TEST_ALL"] require 'minitest/profile' #require "minitest/reporters" #Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new diff --git a/test/mom/blocks/test_block_assign.rb b/test/mom/blocks/test_block_assign.rb new file mode 100644 index 00000000..dbcbc0ef --- /dev/null +++ b/test/mom/blocks/test_block_assign.rb @@ -0,0 +1,21 @@ +require_relative "../helper" + +module Risc + class TestBlockAssign < MiniTest::Test + include Statements + + def setup + super + @input = as_block("a = 5") + @expect = [LoadConstant, SlotToReg, RegToSlot] + end + def test_send_instructions + assert_nil msg = check_nil(:main_block) , msg + end + def test_load_5 + produced = produce_block.next + assert_load( produced , Parfait::Integer) + assert_equal 5 , produced.constant.value + end + end +end diff --git a/test/mom/blocks/test_block_compiler.rb b/test/mom/blocks/test_block_compiler.rb new file mode 100644 index 00000000..84a4d7ba --- /dev/null +++ b/test/mom/blocks/test_block_compiler.rb @@ -0,0 +1,32 @@ +require_relative "../helper" + +module Risc + class TestBlockSetupBlock < MiniTest::Test + include Statements + + def setup + super + @input = as_block("return 5") + @mom = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(as_test_main) + end + def main_risc + @mom.to_risc.method_compilers.find{|c| c.callable.name == :main } + end + def test_mom + assert_equal Mom::MomCollection , @mom.class + end + def test_mom_block_comp + assert_equal 1 , @mom.method_compilers.first.block_compilers.length + end + def test_risc + assert_equal Risc::RiscCollection , @mom.to_risc.class + end + def test_risc_comp + assert_equal :main , main_risc.callable.name + end + def test_risc_block_comp + assert_equal 1 , main_risc.block_compilers.length + end + + end +end diff --git a/test/mom/blocks/test_block_setup.rb b/test/mom/blocks/test_block_setup.rb new file mode 100644 index 00000000..f735989d --- /dev/null +++ b/test/mom/blocks/test_block_setup.rb @@ -0,0 +1,63 @@ +require_relative "../helper" + +module Risc + class TestBlockSetup < MiniTest::Test + include Statements + + def setup + super + @input = as_block("return 5") + @expect = [LoadConstant, SlotToReg, RegToSlot, LoadConstant, SlotToReg, #4 + RegToSlot, LoadConstant, LoadConstant, SlotToReg, SlotToReg, #9 + RegToSlot, RegToSlot, RegToSlot, RegToSlot, SlotToReg, #14 + SlotToReg, RegToSlot, SlotToReg, SlotToReg, SlotToReg, #19 + SlotToReg, RegToSlot, LoadConstant, SlotToReg, RegToSlot, #24 + SlotToReg, FunctionCall, Label] + end + + def test_send_instructions + assert_nil msg = check_nil(:main) , msg + end + def test_load_5 + produced = produce_block.next + assert_load( produced , Parfait::Integer) + assert_equal 5 , produced.constant.value + end + + def test_load_5 + produced = produce_body + assert_load( produced , Parfait::Integer) + assert_equal 5 , produced.constant.value + end + def test_load_block + produced = produce_body.next(3) + assert_load( produced , Parfait::Block) + assert_equal :main_block , produced.constant.name + end + def test_load_method_to_call + produced = produce_body.next(6) + assert_load( produced , Parfait::CallableMethod) + assert_equal :main , produced.constant.name + end + def test_load_next_message + produced = produce_body.next(7) + assert_load( produced , Parfait::Factory) + assert_equal "Message_Type" , produced.constant.for_type.name + end + def test_load_return + produced = produce_body.next(22) + assert_load( produced , Label) + assert produced.constant.name.start_with?("continue_") + end + def test_function_call + produced = produce_body.next(26) + assert_equal FunctionCall , produced.class + assert_equal :main , produced.method.name + end + def test_check_continue + produced = produce_body.next(27) + assert_equal Label , produced.class + assert produced.name.start_with?("continue_") + end + end +end diff --git a/test/mom/builtin/README.md b/test/mom/builtin/README.md new file mode 100644 index 00000000..f390edae --- /dev/null +++ b/test/mom/builtin/README.md @@ -0,0 +1,10 @@ +# Builtin Testing + +At the Module level (word/object/integer) mostly testing that +- functions exist +- they compile +- basic length tests (no "contents") + +Minimal tests for risc compilation, and again length only (should be array too) + +Functionality is tested by interpreter over in interpreter dir diff --git a/test/mom/builtin/helper.rb b/test/mom/builtin/helper.rb new file mode 100644 index 00000000..21f9128c --- /dev/null +++ b/test/mom/builtin/helper.rb @@ -0,0 +1,15 @@ +require_relative "../helper" + +module Mom + module Builtin + class BootTest < MiniTest::Test + def setup + Parfait.boot!(Parfait.default_test_options) + @functions = Builtin.boot_functions + end + def get_compiler( name ) + @functions.each.find{|meth| meth.callable.name == name} + end + end + end +end diff --git a/test/mom/builtin/test_comparison.rb b/test/mom/builtin/test_comparison.rb new file mode 100644 index 00000000..2259705d --- /dev/null +++ b/test/mom/builtin/test_comparison.rb @@ -0,0 +1,30 @@ +require_relative "helper" + +module Mom + module Builtin + class TestIntComp1Risc < BootTest + def setup + super + @method = get_compiler(:<) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 28 , @method.to_risc.risc_instructions.length + end + end + class TestIntComp2Risc < BootTest + def setup + super + @method = get_compiler(:>=) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 27 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_div10.rb b/test/mom/builtin/test_div10.rb new file mode 100644 index 00000000..3958fd21 --- /dev/null +++ b/test/mom/builtin/test_div10.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestIntDiv10Risc < BootTest + def setup + super + @method = get_compiler(:div10) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 76 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_div4.rb b/test/mom/builtin/test_div4.rb new file mode 100644 index 00000000..e143322f --- /dev/null +++ b/test/mom/builtin/test_div4.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestIntDiv4Risc < BootTest + def setup + super + @method = get_compiler(:div4) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 47 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_exit.rb b/test/mom/builtin/test_exit.rb new file mode 100644 index 00000000..612341f2 --- /dev/null +++ b/test/mom/builtin/test_exit.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestObjectExitRisc < BootTest + def setup + super + @method = get_compiler(:exit) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 46 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_get_internal_byte.rb b/test/mom/builtin/test_get_internal_byte.rb new file mode 100644 index 00000000..756a33ea --- /dev/null +++ b/test/mom/builtin/test_get_internal_byte.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestWordGetRisc < BootTest + def setup + super + @method = get_compiler(:get_internal_byte) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 48 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_get_internal_word.rb b/test/mom/builtin/test_get_internal_word.rb new file mode 100644 index 00000000..756a33ea --- /dev/null +++ b/test/mom/builtin/test_get_internal_word.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestWordGetRisc < BootTest + def setup + super + @method = get_compiler(:get_internal_byte) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 48 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_init.rb b/test/mom/builtin/test_init.rb new file mode 100644 index 00000000..ead6f662 --- /dev/null +++ b/test/mom/builtin/test_init.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestObjectInitRisc < BootTest + def setup + super + @method = get_compiler(:__init__) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 37 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_integer.rb b/test/mom/builtin/test_integer.rb new file mode 100644 index 00000000..c8f384b5 --- /dev/null +++ b/test/mom/builtin/test_integer.rb @@ -0,0 +1,71 @@ +require_relative "helper" + +module Mom + module Builtin + class TestIntDiv4 < BootTest + def setup + super + @method = get_compiler(:div4) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestIntDiv10 < BootTest + def setup + super + @method = get_compiler(:div10) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestIntComp1 < BootTest + def setup + super + @method = get_compiler(:<) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestIntComp2 < BootTest + def setup + super + @method = get_compiler(:>=) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestIntOperators < BootTest + def setup + super + end + def each_method &block + Risc.operators.each do |name| + method = get_compiler(name) + block.yield(method) + end + end + def test_has_get_internal + each_method do |method| + assert_equal Mom::MethodCompiler , method.class + assert_equal 5 , method.mom_instructions.length + end + end + end + end +end diff --git a/test/mom/builtin/test_method_missing.rb b/test/mom/builtin/test_method_missing.rb new file mode 100644 index 00000000..70008e4f --- /dev/null +++ b/test/mom/builtin/test_method_missing.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestObjectMissingRisc < BootTest + def setup + super + @method = get_compiler(:method_missing) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 48 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_object.rb b/test/mom/builtin/test_object.rb new file mode 100644 index 00000000..55d13906 --- /dev/null +++ b/test/mom/builtin/test_object.rb @@ -0,0 +1,66 @@ +require_relative "helper" + +module Mom + module Builtin + class TestObjectGet < BootTest + def setup + super + @method = get_compiler(:get_internal_word) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestObjectSet < BootTest + def setup + super + @method = get_compiler(:set_internal_word) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestObjectMissing < BootTest + def setup + super + @method = get_compiler(:method_missing) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestObjectExit < BootTest + def setup + super + @method = get_compiler(:exit) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestObjectInit < BootTest + def setup + super + @method = get_compiler(:__init__) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_operator.rb b/test/mom/builtin/test_operator.rb new file mode 100644 index 00000000..83f7e0c6 --- /dev/null +++ b/test/mom/builtin/test_operator.rb @@ -0,0 +1,27 @@ +require_relative "helper" + +module Mom + module Builtin + class TestIntOperatorsRisc < BootTest + def setup + super + end + def each_method &block + Risc.operators.each do |name| + method = get_compiler(name) + block.yield(method) + end + end + def test_compile + each_method do |method| + assert_equal Risc::MethodCompiler , method.to_risc.class + end + end + def test_risc_length + each_method do |method| + assert_equal 49 , method.to_risc.risc_instructions.length + end + end + end + end +end diff --git a/test/mom/builtin/test_putstring.rb b/test/mom/builtin/test_putstring.rb new file mode 100644 index 00000000..59f2a80f --- /dev/null +++ b/test/mom/builtin/test_putstring.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestWordPutRisc < BootTest + def setup + super + @method = get_compiler(:putstring) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 50 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_set_internal_byte.rb b/test/mom/builtin/test_set_internal_byte.rb new file mode 100644 index 00000000..57eb50d2 --- /dev/null +++ b/test/mom/builtin/test_set_internal_byte.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestWordSetRisc < BootTest + def setup + super + @method = get_compiler(:set_internal_byte) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 22 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_set_internal_word.rb b/test/mom/builtin/test_set_internal_word.rb new file mode 100644 index 00000000..57eb50d2 --- /dev/null +++ b/test/mom/builtin/test_set_internal_word.rb @@ -0,0 +1,18 @@ +require_relative "helper" + +module Mom + module Builtin + class TestWordSetRisc < BootTest + def setup + super + @method = get_compiler(:set_internal_byte) + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 22 , @method.to_risc.risc_instructions.length + end + end + end +end diff --git a/test/mom/builtin/test_word.rb b/test/mom/builtin/test_word.rb new file mode 100644 index 00000000..6f32d960 --- /dev/null +++ b/test/mom/builtin/test_word.rb @@ -0,0 +1,42 @@ +require_relative "helper" + +module Mom + module Builtin + class TestWordPut < BootTest + def setup + super + @method = get_compiler(:putstring) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestWordGet < BootTest + def setup + super + @method = get_compiler(:get_internal_byte) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + class TestWordSet < BootTest + def setup + super + @method = get_compiler(:set_internal_byte) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + end + end +end diff --git a/test/mom/class_send/test_send_simple.rb b/test/mom/class_send/test_send_simple.rb new file mode 100644 index 00000000..9004442c --- /dev/null +++ b/test/mom/class_send/test_send_simple.rb @@ -0,0 +1,43 @@ +require_relative "../helper" + +module Risc + class TestClassCallSimple < MiniTest::Test + include Statements + + def setup + super + @class_input = "def self.simple_return; return 1 ; end;" + @input = "return Test.simple_return" + @expect = [LoadConstant, RegToSlot, Branch] + end + + def test_send_instructions + assert_nil msg = check_nil(:simple_return) , msg + end + def test_load_simple + produced = produce_target(:simple_return).next(1) + assert_load( produced , Parfait::Integer) + assert_equal 1 , produced.constant.value + end + # The normal send + def test_load_5 + produced = produce_body.next(8) + assert_load( produced , Parfait::Class) + assert_equal :Test , produced.constant.name + end + def test_load_label + produced = produce_body.next(11) + assert_load( produced , Label) + end + def test_function_call + produced = produce_body.next(15) + assert_equal FunctionCall , produced.class + assert_equal :simple_return , produced.method.name + end + def test_check_continue + produced = produce_body.next(16) + assert_equal Label , produced.class + assert produced.name.start_with?("continue_") + end + end +end diff --git a/test/mom/helper.rb b/test/mom/helper.rb index d8fac328..d7f69ca0 100644 --- a/test/mom/helper.rb +++ b/test/mom/helper.rb @@ -14,28 +14,37 @@ module Risc SlotToReg, RegToSlot, RegToSlot, SlotToReg, SlotToReg, SlotToReg , FunctionReturn, Label] end - # test hack to in place change object type - def add_space_field(name,type) - class_type = Parfait.object_space.get_type_by_class_name(:Space) - class_type.send(:private_add_instance_variable, name , type) - end def produce_body - produced = produce_instructions + produced = produce_main preamble.each{ produced = produced.next } produced end + + def as_block( block_input , method_input = "main_local = 5") + "#{method_input} ; self.main{|val| #{block_input}}" + end def as_test_main - "class Test; def main(arg);#{@input};end;end" + "class Test; #{@class_input if @class_input};def main(arg);#{@input};end;end" end - def produce_instructions + def to_target assert @expect , "No output given" - linker = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_risc(as_test_main,:interpreter) - compiler = linker.assemblers.find{|c| c.callable.name == :main and c.callable.self_type.object_class.name == :Test} - compiler.instructions + RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_target(as_test_main,:interpreter) end - def check_nil - produced = produce_instructions - compare_instructions( produced , @expect) + def produce_main + produce_target(:main) + end + def produce_block + produce_target(:main_block) + end + def produce_target(name = :main_block) + linker = to_target + block = linker.assemblers.find {|c| c.callable.name == name } + assert_equal Risc::Assembler , block.class + block.instructions + end + def check_nil( name = :main ) + produced = produce_target( name ) + compare_instructions( produced , @expect ) end def check_return was = check_nil diff --git a/test/mom/instruction/helper.rb b/test/mom/instruction/helper.rb index 393dbf5a..7410212f 100644 --- a/test/mom/instruction/helper.rb +++ b/test/mom/instruction/helper.rb @@ -2,5 +2,8 @@ require_relative '../helper' module Mom class InstructionMock < Instruction + def initialize + super("mocking") + end end end diff --git a/test/mom/instruction/test_slot_load.rb b/test/mom/instruction/test_slot_load.rb index 83de985c..600daabd 100644 --- a/test/mom/instruction/test_slot_load.rb +++ b/test/mom/instruction/test_slot_load.rb @@ -4,17 +4,17 @@ module Mom class TestSlotLoadBasics < MiniTest::Test def test_ins_ok - assert SlotLoad.new( [:message, :caller] , [:receiver,:type] ) + assert SlotLoad.new("test", [:message, :caller] , [:receiver,:type] ) end def test_ins_fail1 - assert_raises {SlotLoad.new( [:message, :caller] , nil )} + assert_raises {SlotLoad.new( "test",[:message, :caller] , nil )} end def test_fail_on_right - @load = SlotLoad.new( [:message, :caller] , [:receiver,:type] ) + @load = SlotLoad.new( "test",[:message, :caller] , [:receiver,:type] ) assert_raises {@load.to_risc(Risc::FakeCompiler.new)} end def test_fail_on_left_long - @load = SlotLoad.new( [:message, :caller , :type] , [:receiver,:type] ) + @load = SlotLoad.new("test", [:message, :caller , :type] , [:receiver,:type] ) assert_raises {@load.to_risc(Risc::FakeCompiler.new)} end end diff --git a/test/mom/instruction/test_slot_load1.rb b/test/mom/instruction/test_slot_load1.rb index 66e9fbb0..a3ce9139 100644 --- a/test/mom/instruction/test_slot_load1.rb +++ b/test/mom/instruction/test_slot_load1.rb @@ -5,7 +5,7 @@ module Mom def setup Parfait.boot!(Parfait.default_test_options) - load = SlotLoad.new( [:message, :caller] , [:message,:type] ) + load = SlotLoad.new("test", [:message, :caller] , [:message,:type] ) @compiler = Risc::FakeCompiler.new load.to_risc(@compiler) @instructions = @compiler.instructions diff --git a/test/mom/instruction/test_slot_load2.rb b/test/mom/instruction/test_slot_load2.rb index 3f8f3dd3..4a4aa637 100644 --- a/test/mom/instruction/test_slot_load2.rb +++ b/test/mom/instruction/test_slot_load2.rb @@ -6,7 +6,7 @@ module Mom def setup Parfait.boot!(Parfait.default_test_options) @compiler = Risc::FakeCompiler.new - load = SlotLoad.new( [:message, :caller, :type] , [:message, :caller , :type] ) + load = SlotLoad.new( "test",[:message, :caller, :type] , [:message, :caller , :type] ) load.to_risc(@compiler) @instructions = @compiler.instructions end diff --git a/test/mom/instruction/test_slot_load3.rb b/test/mom/instruction/test_slot_load3.rb index e7fac0ef..b493ca59 100644 --- a/test/mom/instruction/test_slot_load3.rb +++ b/test/mom/instruction/test_slot_load3.rb @@ -8,7 +8,7 @@ module Mom method = make_method @compiler = Risc::FakeCompiler.new @cache_entry = Parfait::CacheEntry.new(method.frame_type, method) - load = SlotLoad.new( [@cache_entry , :cached_type] , [:message, :type] ) + load = SlotLoad.new("test", [@cache_entry , :cached_type] , [:message, :type] ) load.to_risc(@compiler) @instructions = @compiler.instructions end diff --git a/test/mom/test_block_compiler.rb b/test/mom/test_block_compiler.rb new file mode 100644 index 00000000..c4f50a66 --- /dev/null +++ b/test/mom/test_block_compiler.rb @@ -0,0 +1,23 @@ +require_relative "helper" + +module Mom + class TestBlockCompiler < MiniTest::Test + include ScopeHelper + + def setup + code = as_test_main_block("return 5" , "a = 1") + @risc = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_risc(code) + end + + def test_collection + assert_equal Risc::RiscCollection, @risc.class + end + def test_main_compiler + assert_equal :main , @risc.method_compilers.first.callable.name + end + def test_main_block_compiler + assert_equal :main , @risc.method_compilers.first.block_compilers.first.in_method.name + assert_equal :main_block , @risc.method_compilers.first.block_compilers.first.callable.name + end + end +end diff --git a/test/mom/test_block_statement.rb b/test/mom/test_block_statement.rb index f79a9fbb..3216b4c0 100644 --- a/test/mom/test_block_statement.rb +++ b/test/mom/test_block_statement.rb @@ -10,7 +10,7 @@ module Vool @ret = compile_mom( as_test_main("self.main {|elem| elem = 5 } ")) end def test_is_compiler - assert_equal Mom::MomCompiler , @ret.class + assert_equal Mom::MomCollection , @ret.class end def test_has_method assert_equal Parfait::CallableMethod , @ret.method_compilers.first.get_method.class diff --git a/test/risc/test_builtin.rb b/test/mom/test_builtin.rb similarity index 58% rename from test/risc/test_builtin.rb rename to test/mom/test_builtin.rb index e1b4e020..3ccdde52 100644 --- a/test/risc/test_builtin.rb +++ b/test/mom/test_builtin.rb @@ -1,22 +1,23 @@ require_relative "helper" -module Risc +module Mom class TestBuiltinFunction < MiniTest::Test def setup Parfait.boot!(Parfait.default_test_options) + @functions = Builtin.boot_functions end def test_has_boot_function - assert Builtin.boot_functions + assert @functions end def test_boot_function_type - assert_equal Array, Builtin.boot_functions.class + assert_equal Array, @functions.class end def test_boot_function_length - assert_equal 23, Builtin.boot_functions.length + assert_equal 22, @functions.length end def test_boot_function_first - assert_equal MethodCompiler, Builtin.boot_functions.first.class + assert_equal Mom::MethodCompiler, @functions.first.class end end end diff --git a/test/mom/test_callable_compiler.rb b/test/mom/test_callable_compiler.rb new file mode 100644 index 00000000..5652295e --- /dev/null +++ b/test/mom/test_callable_compiler.rb @@ -0,0 +1,32 @@ +require_relative "helper" +class FakeCallable +end +module Mom + class FakeCallableCompiler < CallableCompiler + def source_name + "luke" + end + end + class TestCallableCompiler < MiniTest::Test + + def setup + @compiler = FakeCallableCompiler.new(FakeCallable.new) + 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 @compiler.source_name , @compiler.current.name + end + def test_mom + assert @compiler.mom_instructions + end + def test_const + assert_equal Array , @compiler.constants.class + end + end +end diff --git a/test/mom/test_class_statement.rb b/test/mom/test_class_statement.rb index b3f48a50..55e24d3f 100644 --- a/test/mom/test_class_statement.rb +++ b/test/mom/test_class_statement.rb @@ -2,7 +2,7 @@ require_relative "helper" module Vool - class TestClassStatement < MiniTest::Test + class TestClassStatementMom < MiniTest::Test include MomCompile def setup @@ -11,10 +11,10 @@ module Vool end def test_return_class - assert_equal Mom::MomCompiler , @ret.class + assert_equal Mom::MomCollection , @ret.class end def test_has_compilers - assert_equal Risc::MethodCompiler , @ret.method_compilers.first.class + assert_equal Mom::MethodCompiler , @ret.method_compilers.first.class end def test_constant diff --git a/test/mom/test_instruction.rb b/test/mom/test_instruction.rb new file mode 100644 index 00000000..82b0d5d7 --- /dev/null +++ b/test/mom/test_instruction.rb @@ -0,0 +1,20 @@ + +require_relative "helper" + +module Mom + class TestInstruction < MiniTest::Test + + def test_instantiates + assert Instruction.new("Hi") + end + def test_string_source + assert_equal "Hi" ,Instruction.new("Hi").source + end + def test_nil_next + assert_nil Instruction.new("Hi").next + end + def test_raise + assert_raises {Instruction.new(5)} + end + end +end diff --git a/test/mom/test_method_compiler.rb b/test/mom/test_method_compiler.rb new file mode 100644 index 00000000..9ccf5d1d --- /dev/null +++ b/test/mom/test_method_compiler.rb @@ -0,0 +1,36 @@ +require_relative "helper" + +module Mom + class TestMethodCompiler < MiniTest::Test + include ScopeHelper + + def setup + end + + def in_test_vool(body = "@ivar = 5") + code = in_Test("def meth; #{body};end") + RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(code) + end + + def test_method + in_test_vool() + method = Parfait.object_space.get_class_by_name(:Test).get_method(:meth) + assert_equal Parfait::VoolMethod , method.class + end + def test_method_mom_col + mom = in_test_vool() + assert_equal Mom::MomCollection , mom.class + assert_equal Mom::MethodCompiler , mom.compilers.first.class + end + def test_compiles_risc + compiler = in_test_vool().compilers.first.to_risc + assert_equal Risc::MethodCompiler , compiler.class + assert_equal Risc::Label , compiler.risc_instructions.class + end + def test_compiles_all_risc + compiler = in_test_vool().compilers.first.to_risc + assert_equal Risc::LoadConstant , compiler.risc_instructions.next.class + assert_equal 17 , compiler.risc_instructions.length + end + end +end diff --git a/test/mom/test_mom_collection.rb b/test/mom/test_mom_collection.rb new file mode 100644 index 00000000..4328e39b --- /dev/null +++ b/test/mom/test_mom_collection.rb @@ -0,0 +1,54 @@ +require_relative "helper" + +module Mom + class TestMomCollection < MiniTest::Test + include MomCompile + + def setup + Parfait.boot!(Parfait.default_test_options) + @comp = compile_mom( "class Test ; def main(); return 'Hi'; end; end;") + end + + def test_class + assert_equal MomCollection , @comp.class + end + def test_compilers + assert_equal 22 , @comp.compilers.length + end + def test_boot_compilers + assert_equal 21 , @comp.boot_compilers.length + end + def test_compilers_bare + assert_equal 21 , MomCollection.new.compilers.length + end + def test_append_class + assert_equal MomCollection, (@comp.append @comp).class + end + def test_append_length + assert_equal 2 , @comp.append(@comp).method_compilers.length + end + end + class TestMomCollectionToRisc < MiniTest::Test + include MomCompile + + def setup + Parfait.boot!(Parfait.default_test_options) + @comp = compile_mom( "class Test ; def main(); return 'Hi'; end; end;") + @collection = @comp.to_risc() + end + def compiler + @collection.method_compilers.first + end + def test_has_to_risc + assert_equal Risc::RiscCollection, @collection.class + end + def test_has_risc_compiler + assert_equal Risc::MethodCompiler, compiler.class + assert_equal 22, @collection.method_compilers.length + end + def test_has_risc_instructions + assert_equal Risc::Label, compiler.risc_instructions.class + assert_equal 17, compiler.risc_instructions.length + end + end +end diff --git a/test/mom/test_mom_compiler.rb b/test/mom/test_mom_compiler.rb deleted file mode 100644 index 5ba6c0c3..00000000 --- a/test/mom/test_mom_compiler.rb +++ /dev/null @@ -1,40 +0,0 @@ -require_relative "helper" - -module Mom - class TestMomCompiler < MiniTest::Test - include MomCompile - - def setup - Parfait.boot!(Parfait.default_test_options) - @comp = compile_mom( "class Test ; def main(); return 'Hi'; end; end;") - end - - def test_class - assert_equal MomCompiler , @comp.class - end - def test_compilers - assert_equal 23 , @comp.compilers.length - end - def test_boot_compilers - assert_equal 22 , @comp.boot_compilers.length - end - def test_compilers_bare - assert_equal 22 , MomCompiler.new.compilers.length - end - def test_returns_constants - assert_equal Array , @comp.constants.class - end - def test_has_constant - assert_equal "Hi" , @comp.constants[1].to_string - end - def test_has_translate - assert @comp.translate(:interpreter) - end - def test_append_class - assert_equal MomCompiler, (@comp.append @comp).class - end - def test_append_length - assert_equal 2 , @comp.append(@comp).method_compilers.length - end - end -end diff --git a/test/mom/test_return_sequence.rb b/test/mom/test_return_sequence.rb index 71409046..b07d7310 100644 --- a/test/mom/test_return_sequence.rb +++ b/test/mom/test_return_sequence.rb @@ -8,10 +8,9 @@ module Risc super @input = "5.div4" @expect = "something" - @produced = produce_instructions end def instruction(num) # 18 is the main, see length in test/mom/send/test_setup_simple.rb - @produced.next( 18 + num) + produce_main.next( 18 + num) end def test_postamble_classes postamble.each_with_index do |ins , index| diff --git a/test/parfait/test_space2.rb b/test/parfait/test_space2.rb index 0b08895d..4b1b519c 100644 --- a/test/parfait/test_space2.rb +++ b/test/parfait/test_space2.rb @@ -4,11 +4,11 @@ module Parfait class TestMethods < ParfaitTest def setup super - Risc::Builtin.boot_functions + Mom.boot! end def test_integer int = Parfait.object_space.get_class_by_name :Integer - assert_equal 14, int.instance_type.method_names.get_length + assert_equal 13, int.instance_type.method_names.get_length end def test_methods_booted word = @space.get_type_by_class_name(:Word) diff --git a/test/parfait/test_vool_method.rb b/test/parfait/test_vool_method.rb new file mode 100644 index 00000000..30a3e8ea --- /dev/null +++ b/test/parfait/test_vool_method.rb @@ -0,0 +1,32 @@ +require_relative "helper" + +module Vool + class TestVoolMethod < MiniTest::Test + include VoolCompile + + def setup + Parfait.boot!(Parfait.default_test_options) + ruby_tree = Ruby::RubyCompiler.compile( as_test_main("a = 5") ) + @clazz = ruby_tree.to_vool + end + def method + @clazz.body.first + end + def test_setup + assert_equal ClassStatement , @clazz.class + assert_equal Statements , @clazz.body.class + assert_equal MethodStatement , method.class + end + def test_class + assert_equal Parfait::Class , @clazz.create_class_object.class + end + def test_method + clazz = @clazz.create_class_object + assert_equal Parfait::VoolMethod , method.make_method(clazz).class + end + + #create CallableMethod + + #create Compiler + end +end diff --git a/test/risc/builtin/helper.rb b/test/risc/builtin/helper.rb deleted file mode 100644 index 68357f88..00000000 --- a/test/risc/builtin/helper.rb +++ /dev/null @@ -1,11 +0,0 @@ -require_relative "../helper" - -module Risc - module Builtin - class BuiltinTest < MiniTest::Test - include Ticker - def setup - end - end - end -end diff --git a/test/risc/builtin/README.md b/test/risc/interpreter/builtin/README.md similarity index 100% rename from test/risc/builtin/README.md rename to test/risc/interpreter/builtin/README.md diff --git a/test/risc/builtin/test_int_cmp.rb b/test/risc/interpreter/builtin/test_int_cmp.rb similarity index 92% rename from test/risc/builtin/test_int_cmp.rb rename to test/risc/interpreter/builtin/test_int_cmp.rb index e3ed2866..e9024ee6 100644 --- a/test/risc/builtin/test_int_cmp.rb +++ b/test/risc/interpreter/builtin/test_int_cmp.rb @@ -1,8 +1,12 @@ -require_relative "helper" +require_relative "../helper" +# TODO move these to interpreter dir module Risc module Builtin - class IntCmp < BuiltinTest + class IntCmp < Minitest::Test + include Ticker + def setup + end def test_smaller_true run_main_return "4 < 5" diff --git a/test/risc/builtin/test_int_math.rb b/test/risc/interpreter/builtin/test_int_math.rb similarity index 88% rename from test/risc/builtin/test_int_math.rb rename to test/risc/interpreter/builtin/test_int_math.rb index fe9fd893..514e947e 100644 --- a/test/risc/builtin/test_int_math.rb +++ b/test/risc/interpreter/builtin/test_int_math.rb @@ -1,8 +1,11 @@ -require_relative "helper" +require_relative "../helper" module Risc module Builtin - class IntMath < BuiltinTest + class IntMath < Minitest::Test + include Ticker + def setup + end def test_add run_main_return "5 + 5" diff --git a/test/risc/interpreter/calling/test_minus.rb b/test/risc/interpreter/calling/test_minus.rb index d1f419ea..304ca87c 100644 --- a/test/risc/interpreter/calling/test_minus.rb +++ b/test/risc/interpreter/calling/test_minus.rb @@ -41,7 +41,7 @@ module Risc ret = main_ticks(68) assert_equal FunctionReturn , ret.class assert_equal :r1 , ret.register.symbol - assert_equal 24204 , @interpreter.get_register(ret.register) + assert_equal 23196 , @interpreter.get_register(ret.register) end end end diff --git a/test/risc/position/test_code_listener1.rb b/test/risc/position/test_code_listener1.rb index dccfdb5f..bb528e3d 100644 --- a/test/risc/position/test_code_listener1.rb +++ b/test/risc/position/test_code_listener1.rb @@ -5,7 +5,7 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) Risc.boot! - @linker = Mom::MomCompiler.new.translate(:interpreter) + @linker = Mom::MomCollection.new.to_risc.translate(:interpreter) @binary = Parfait::BinaryCode.new(1) @method = Parfait.object_space.types.values.first.methods @label = Risc.label("hi","ho") diff --git a/test/risc/position/test_position3.rb b/test/risc/position/test_position3.rb index 5a4060fe..b41a4a55 100644 --- a/test/risc/position/test_position3.rb +++ b/test/risc/position/test_position3.rb @@ -4,8 +4,9 @@ module Risc class TestMachinePositions < MiniTest::Test def setup_for(platform) Parfait.boot!(Parfait.default_test_options) + Mom.boot! Risc.boot! - @linker = Mom::MomCompiler.new.translate(platform) + @linker = Mom::MomCollection.new.to_risc.translate(platform) @linker.position_all end def test_cpu_init diff --git a/test/risc/test_builder.rb b/test/risc/test_builder.rb index e0fcf969..6bf06c2a 100644 --- a/test/risc/test_builder.rb +++ b/test/risc/test_builder.rb @@ -5,9 +5,10 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) + Mom.boot! Risc.boot! init = Parfait.object_space.get_init - @builder = Risc::MethodCompiler.new( init ).builder(init) + @builder = Risc::MethodCompiler.new( init ,Mom::Label.new( "source_name", "return_label")).builder(init) @label = Risc.label("source","name") @start = @builder.compiler.current end diff --git a/test/risc/test_builder1.rb b/test/risc/test_builder1.rb index c132fb5c..74ee6633 100644 --- a/test/risc/test_builder1.rb +++ b/test/risc/test_builder1.rb @@ -5,9 +5,10 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) + Mom.boot! Risc.boot! @init = Parfait.object_space.get_init - @compiler = Risc::MethodCompiler.new( @init ) + @compiler = Risc::MethodCompiler.new( @init , Mom::Label.new( "source_name", "return_label")) @builder = @compiler.builder(@init) end def test_inserts_built @@ -42,7 +43,7 @@ module Risc end def test_allocate_len int = @builder.allocate_int - assert_equal 41 , @builder.compiler.risc_instructions.length + assert_equal 28 , @builder.compiler.risc_instructions.length end end end diff --git a/test/risc/test_builder2.rb b/test/risc/test_builder2.rb index 8f6feb15..0f61bba2 100644 --- a/test/risc/test_builder2.rb +++ b/test/risc/test_builder2.rb @@ -5,9 +5,10 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) + Mom.boot! Risc.boot! @init = Parfait.object_space.get_init - @compiler = Risc::MethodCompiler.new( @init ) + @compiler = Risc::MethodCompiler.new( @init, Mom::Label.new( "source_name", "return_label") ) @builder = @compiler.builder(@init) end def test_list diff --git a/test/risc/test_callable_compiler.rb b/test/risc/test_callable_compiler.rb new file mode 100644 index 00000000..9d7022dd --- /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,c) + super(a,c) + end + def source_name + "luke" + end + end + class TestCallableCompiler < MiniTest::Test + + def setup + Parfait.boot!({}) + label = Mom::Label.new("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 diff --git a/test/risc/test_collector.rb b/test/risc/test_collector.rb index bd45435d..dfa05c0c 100644 --- a/test/risc/test_collector.rb +++ b/test/risc/test_collector.rb @@ -6,12 +6,12 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) Risc.boot! - @linker = Mom::MomCompiler.new.translate(:arm) + @linker = Mom::MomCollection.new.to_risc.translate(:arm) end def test_simple_collect objects = Collector.collect_space(@linker) - assert_equal 600 , objects.length , objects.length.to_s + assert_equal 621 , objects.length , objects.length.to_s end def test_collect_all_types @@ -47,15 +47,15 @@ module Risc def setup opt = Parfait.default_test_options - opt[:factory] = 4000 + opt[:factory] = 400 Parfait.boot!(opt) Risc.boot! - @linker = Mom::MomCompiler.new.translate(:arm) + @linker = Mom::MomCollection.new.to_risc.translate(:arm) end def test_simple_collect objects = Collector.collect_space(@linker) - assert_equal 20329, objects.length , objects.length.to_s + assert_equal 2421, objects.length , objects.length.to_s end def test_integer_positions diff --git a/test/risc/test_interpreter.rb b/test/risc/test_interpreter.rb index 8e77f8c2..67e9d436 100644 --- a/test/risc/test_interpreter.rb +++ b/test/risc/test_interpreter.rb @@ -4,8 +4,9 @@ module Risc class TestInterpreterBasics < MiniTest::Test def setup Parfait.boot!(Parfait.default_test_options) + Mom.boot! Risc.boot! - @linker = Mom::MomCompiler.new.translate(:interpreter) + @linker = Mom::MomCollection.new.to_risc.translate(:interpreter) end def test_class @@ -54,7 +55,7 @@ module Risc end def test_pc1 @interpreter.tick - assert_equal 23672 , @interpreter.pc + assert_equal 22856 , @interpreter.pc end def test_tick2 @interpreter.tick @@ -68,7 +69,7 @@ module Risc def test_pc2 @interpreter.tick @interpreter.tick - assert_equal 23676 , @interpreter.pc + assert_equal 22860 , @interpreter.pc end def test_tick_14_jump 14.times {@interpreter.tick} diff --git a/test/risc/test_linker.rb b/test/risc/test_linker.rb index fb506201..97125519 100644 --- a/test/risc/test_linker.rb +++ b/test/risc/test_linker.rb @@ -6,7 +6,7 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) Risc.boot! - @linker = Mom::MomCompiler.new.translate(:arm) + @linker = Mom::MomCollection.new.to_risc.translate(:arm) end def test_objects objects = @linker.object_positions @@ -25,7 +25,7 @@ module Risc assert_equal 0 , Position.get(@linker.cpu_init).at end def test_cpu_at - assert_equal "0x569c" , Position.get(@linker.cpu_init.first).to_s + assert_equal "0x563c" , Position.get(@linker.cpu_init.first).to_s end def test_cpu_label assert_equal Position , Position.get(@linker.cpu_init.first).class diff --git a/test/risc/test_linker1.rb b/test/risc/test_linker1.rb index 8d846477..f4c101c2 100644 --- a/test/risc/test_linker1.rb +++ b/test/risc/test_linker1.rb @@ -4,8 +4,7 @@ module Risc class TestMachinePos < MiniTest::Test def setup code = "class Space; def main(arg);a = 1;return a;end;end" - @linker = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_risc(code,:arm) - @linker.position_all + @linker = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_binary(code, :arm) end def test_positions_set @linker.object_positions.each do |obj , position| @@ -17,7 +16,7 @@ module Risc assert_equal 1 , mains.length end def test_assembler_num - assert_equal 23 , @linker.assemblers.length + assert_equal 22 , @linker.assemblers.length end end end diff --git a/test/risc/test_method_compiler.rb b/test/risc/test_method_compiler.rb index b791ecb2..f2516592 100644 --- a/test/risc/test_method_compiler.rb +++ b/test/risc/test_method_compiler.rb @@ -12,9 +12,6 @@ module Risc vool.to_mom(nil) vool end - def in_test_mom(str) - FIXMERubyX::RubyXCompiler.new(in_Test(str)).ruby_to_mom() - end def create_method(body = "@ivar = 5") in_test_vool("def meth; #{body};end") test = Parfait.object_space.get_class_by_name(:Test) @@ -65,19 +62,11 @@ module Risc end def constant_setup(input) mom = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(in_Test(input)) - assert_equal Mom::MomCompiler , mom.class + assert_equal Mom::MomCollection , mom.class compiler = mom.method_compilers.first - assert_equal MethodCompiler , compiler.class + assert_equal Mom::MethodCompiler , compiler.class compiler end - def test_has_method_constant - compiler = constant_setup("def meth; return 'Hi';end") - assert compiler.constants.include?("Hi") - end - def test_has_block_constant - compiler = constant_setup("def meth; meth{return 'Ho'};return 'Hi';end") - assert compiler.constants.include?("Ho") - end def test_return_label compiler = constant_setup("def meth; return 'Hi';end") assert_equal "return_label", compiler.return_label.name diff --git a/test/mom/test_mom_compiler1.rb b/test/risc/test_risc_collection.rb similarity index 77% rename from test/mom/test_mom_compiler1.rb rename to test/risc/test_risc_collection.rb index 402238a7..bcf2af81 100644 --- a/test/mom/test_mom_compiler1.rb +++ b/test/risc/test_risc_collection.rb @@ -1,17 +1,17 @@ require_relative "helper" -module Mom +module Risc class TestMomCompilerTranslate < MiniTest::Test include MomCompile def setup Parfait.boot!(Parfait.default_test_options) @comp = compile_mom( "class Test ; def main(); main{return 'Ho'};return 'Hi'; end; end;") - @linker = @comp.translate(:interpreter) + @linker = @comp.to_risc.translate(:interpreter) end def test_translate_class - assert_equal Risc::Linker , @linker.class + assert_equal Linker , @linker.class end def test_linker_has_constants assert_equal Array , @linker.constants.class @@ -26,16 +26,16 @@ module Mom assert @linker.constants.include?("Ho") end def test_translate_platform - assert_kind_of Risc::Platform , @linker.platform + assert_kind_of Platform , @linker.platform end def test_translate_assemblers - assert_equal Risc::Assembler , @linker.assemblers.first.class + assert_equal Assembler , @linker.assemblers.first.class end def test_assembler_code - assert_equal Risc::Label , @linker.assemblers.first.instructions.class + assert_equal Label , @linker.assemblers.first.instructions.class end def test_assembler_assembled - assert_equal Risc::LoadConstant , @linker.assemblers.first.instructions.next.class + assert_equal LoadConstant , @linker.assemblers.first.instructions.next.class end def test_no_loops_in_chain @linker.assemblers.each do |asm| diff --git a/test/risc/test_risc_compiler.rb b/test/risc/test_risc_compiler.rb new file mode 100644 index 00000000..9347477e --- /dev/null +++ b/test/risc/test_risc_compiler.rb @@ -0,0 +1,58 @@ +require_relative "helper" + +module Risc + class TestMomCompilerTranslate < MiniTest::Test + include MomCompile + + def setup + @comp = compile_mom( "class Test ; def main(); main{return 'Ho'};return 'Hi'; end; end;") + @linker = @comp.to_risc.translate(:interpreter) + end + + def test_translate_class + assert_equal Linker , @linker.class + end + def test_linker_has_constants + assert_equal Array , @linker.constants.class + end + def test_linker_constants_not_empty + assert !@linker.constants.empty? + end + def test_linker_constants_contains_hi + assert @linker.constants.include?("Hi") + end + def test_linker_constants_contains_ho + assert @linker.constants.include?("Ho") + end + def test_translate_platform + assert_kind_of Platform , @linker.platform + end + def test_translate_assemblers + assert_equal Assembler , @linker.assemblers.first.class + end + def test_assembler_code + assert_equal Label , @linker.assemblers.first.instructions.class + end + def test_assembler_assembled + assert_equal LoadConstant , @linker.assemblers.first.instructions.next.class + end + def test_no_loops_in_chain + @linker.assemblers.each do |asm| + all = [] + asm.instructions.each do |ins| + assert !all.include?(ins) , "Double in #{asm.callable.name}:#{ins}" + all << ins + end + end + end + def test_no_risc + @linker.position_all + @linker.create_binary + @linker.assemblers.each do |asm| + asm.instructions.each do |ins| + ins.assemble(Util::DevNull.new) + end # risc instruction don't have an assemble + end + end + end +end diff --git a/test/risc/test_text_writer.rb b/test/risc/test_text_writer.rb index fe6c931a..42e3b5d6 100644 --- a/test/risc/test_text_writer.rb +++ b/test/risc/test_text_writer.rb @@ -6,7 +6,7 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) Risc.boot! - @linker = Mom::MomCompiler.new.translate(:arm) + @linker = Mom::MomCollection.new.to_risc.translate(:arm) end def test_init @text_writer = TextWriter.new(@linker) @@ -21,7 +21,7 @@ module Risc def setup Parfait.boot!(Parfait.default_test_options) Risc.boot! - @linker = Mom::MomCompiler.new.translate(:arm) + @linker = Mom::MomCollection.new.to_risc.translate(:arm) @linker.position_all @linker.create_binary @text_writer = TextWriter.new(@linker) diff --git a/test/rubyx/helper.rb b/test/rubyx/helper.rb index d6f7a191..ae58aa8b 100644 --- a/test/rubyx/helper.rb +++ b/test/rubyx/helper.rb @@ -5,10 +5,6 @@ module RubyX module RubyXHelper def setup end - def ruby_to_risc(input , options = {}) - mom = ruby_to_mom(input , options) - mom.translate(options[:platform] || :interpreter) - end def ruby_to_vool(input, options = {}) options = RubyX.default_test_options.merge(options) RubyXCompiler.new(options).ruby_to_vool(input) diff --git a/test/rubyx/test_rubyx_compiler2.rb b/test/rubyx/test_rubyx_compiler2.rb index 5d34231a..6979383e 100644 --- a/test/rubyx/test_rubyx_compiler2.rb +++ b/test/rubyx/test_rubyx_compiler2.rb @@ -8,29 +8,35 @@ module RubyX def setup super code = "class Space ; def main(arg);return arg;end; end" - @linker = ruby_to_risc(code) + @comp = RubyXCompiler.new(load_parfait: true ) + @collection = @comp.ruby_to_risc(code) end def test_to_risc - assert_equal Risc::Linker , @linker.class + assert_equal Risc::RiscCollection , @collection.class + end + def test_linker + assert_equal Risc::Linker , @collection.translate(:interpreter).class end def test_method - assert_equal :main , @linker.assemblers.first.callable.name + linker = @collection.translate(:interpreter) + assert_equal :main , linker.assemblers.first.callable.name end def test_asm_len - assert_equal 23 , @linker.assemblers.length + linker = @collection.translate(:interpreter) + assert_equal 22 , linker.assemblers.length end end - class TestRubyXCompilerParfait < MiniTest::Test + class TestRubyXCompilerParfait #< MiniTest::Test include ScopeHelper include RubyXHelper def setup super - code = "class Space ; def self.class_method; return 1; end;def main(arg);return Space.class_method;end; end" - @comp = RubyXCompiler.ruby_to_binary(code , load_parfait: true , platform: :interpreter) + code = "class Space ; def self.class_method(); return 1; end;def main(arg);return Space.class_method;end; end" + @comp = RubyXCompiler.ruby_to_risc(code , load_parfait: true)# , platform: :interpreter) end - def pest_load + def test_load object = Parfait.object_space.get_class_by_name(:Object) assert_equal Parfait::Class , object.class object = object.instance_type diff --git a/test/rubyx/test_rubyx_compiler3.rb b/test/rubyx/test_rubyx_compiler3.rb index 40cf80a9..471987fc 100644 --- a/test/rubyx/test_rubyx_compiler3.rb +++ b/test/rubyx/test_rubyx_compiler3.rb @@ -33,9 +33,10 @@ module RubyX compiler = RubyXCompiler.new(RubyX.default_test_options) compiler.ruby_to_vool(space_source_for("main")) compiler.ruby_to_vool(space_source_for("twain")) + assert_equal 2 , compiler.vool.length linker = compiler.to_binary(:interpreter) assert_equal Risc::Linker , linker.class - assert_equal 24 , linker.assemblers.length + assert_equal 23 , linker.assemblers.length end end end diff --git a/test/support/compiling.rb b/test/support/compiling.rb index 171724f6..9b74717b 100644 --- a/test/support/compiling.rb +++ b/test/support/compiling.rb @@ -16,43 +16,34 @@ module ScopeHelper def as_test_main( statements ) in_Test("def main(arg) ; #{statements}; end") end -end -module MomCompile - include ScopeHelper - - def compile_method(input) - statements = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_vool(input) - assert statements.is_a?(Vool::ClassStatement) - ret = statements.to_mom(nil) - assert_equal Parfait::Class , statements.clazz.class , statements - @method = statements.clazz.get_method(:main) - assert_equal Parfait::VoolMethod , @method.class - ret + def as_test_main_block( block_input = "return 5", method_input = "main_local = 5") + as_test_main("#{method_input} ; self.main{|val| #{block_input}}") end + +end +module VoolCompile + include ScopeHelper + include Mom + + def compile_first_method( input ) - ret = compile_method( as_test_main( input )) - assert_equal Mom::MomCompiler , ret.class - compiler = ret.method_compilers.find{|c| c.get_method.name == :main and c.get_method.self_type.object_class.name == :Test} - assert_equal Risc::MethodCompiler , compiler.class - @method.source.to_mom( compiler ) + input = as_test_main( input ) + collection = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(input) + assert collection.is_a?(Mom::MomCollection) , collection.class.name + compiler = collection.compilers.first + assert compiler.is_a?(Mom::MethodCompiler) + assert_equal Mom::MethodCompiler , compiler.class + compiler end def compile_first_block( block_input , method_input = "main_local = 5") - source = "#{method_input} ; self.main{|val| #{block_input}}" - vool = Ruby::RubyCompiler.compile( as_test_main(source) ).to_vool - mom_c = vool.to_mom(nil) - compiler = mom_c.method_compilers.find{|c| c.get_method.name == :main and c.get_method.self_type.object_class.name == :Test} - block = nil - vool.each {|b| block = b if b.is_a?(Vool::BlockStatement)} + source = as_test_main("#{method_input} ; self.main{|val| #{block_input}}") + mom_col = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom( source ) + compiler = mom_col.method_compilers.find{|c| c.get_method.name.to_s.start_with?("main") } + block = compiler.block_compilers.first assert block - block_c = compiler.block_compilers.first - assert block_c - block.body.to_mom(block_c) + block.mom_instructions.next end - def compile_mom(input) - RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(input) - end - def check_array( should , is ) index = 0 test = is @@ -79,26 +70,11 @@ module MomCompile end +module MomCompile + include ScopeHelper - - -class Ignored - def == other - return false unless other.class == self.class - Sof::Util.attributes(self).each do |a| - begin - left = send(a) - rescue NoMethodError - next # not using instance variables that are not defined as attr_readers for equality - end - begin - right = other.send(a) - rescue NoMethodError - return false - end - return false unless left.class == right.class - return false unless left == right - end - return true + def compile_mom(input) + RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(input) end + end diff --git a/test/vool/blocks/test_assign.rb b/test/vool/blocks/test_assign.rb index d8d2624c..e7966b2b 100644 --- a/test/vool/blocks/test_assign.rb +++ b/test/vool/blocks/test_assign.rb @@ -2,13 +2,12 @@ require_relative "../helper" module VoolBlocks class TestAssignMom < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_block( "local = 5") + @ins = compile_first_block( "local = 5" ) end - def test_block_compiles assert_equal Mom::SlotLoad , @ins.class , @ins end @@ -30,7 +29,7 @@ module VoolBlocks end class TestAssignMomInstanceToLocal < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) @ins = compile_first_block( "local = @a" , "@a = 5") #second arg in method scope @@ -47,7 +46,7 @@ module VoolBlocks end class TestAssignToArg < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) @@ -66,7 +65,7 @@ module VoolBlocks end class TestAssignMomToInstance < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) end diff --git a/test/vool/blocks/test_class_blocks.rb b/test/vool/blocks/test_class_blocks.rb index 3dd436e1..d0b0cdc7 100644 --- a/test/vool/blocks/test_class_blocks.rb +++ b/test/vool/blocks/test_class_blocks.rb @@ -2,7 +2,6 @@ require_relative "../helper" module VoolBlocks class TestClassAssignMom < MiniTest::Test - include MomCompile def setup Parfait.boot!(Parfait.default_test_options) @@ -21,7 +20,7 @@ module VoolBlocks end def test_assign_compiles vool = Ruby::RubyCompiler.compile( as_class_method("val = 0") ).to_vool - assert_equal Mom::MomCompiler , vool.to_mom(nil).class + assert_equal Mom::MomCollection , vool.to_mom(nil).class end end end diff --git a/test/vool/blocks/test_if_condition.rb b/test/vool/blocks/test_if_condition.rb index 9ee3696c..052cc3a5 100644 --- a/test/vool/blocks/test_if_condition.rb +++ b/test/vool/blocks/test_if_condition.rb @@ -2,12 +2,11 @@ require_relative "helper" module VoolBlocks class TestConditionIfMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - Risc::Builtin.boot_functions + Mom::Builtin.boot_functions @ins = compile_first_block( "if(5.div4) ; @a = 6 ; else; @a = 5 ; end") end @@ -23,7 +22,8 @@ module VoolBlocks end def test_array check_array [MessageSetup, ArgumentTransfer, SimpleCall, SlotLoad, TruthCheck, Label , - SlotLoad, Jump, Label, SlotLoad, Label] , @ins + SlotLoad, Jump, Label, SlotLoad, Label, + Label, ReturnSequence, Label] , @ins end end diff --git a/test/vool/blocks/test_while_simple.rb b/test/vool/blocks/test_while_simple.rb index 8c6d53a2..4219d408 100644 --- a/test/vool/blocks/test_while_simple.rb +++ b/test/vool/blocks/test_while_simple.rb @@ -2,8 +2,7 @@ require_relative "helper" module VoolBlocks class TestSimpleWhileMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) @@ -20,7 +19,8 @@ module VoolBlocks assert_equal SlotDefinition , @ins.next.condition.class , @ins end def test_array - check_array [Label, TruthCheck, SlotLoad, Jump, Label], @ins + check_array [Label, TruthCheck, SlotLoad, Jump, Label, + Label, ReturnSequence, Label], @ins end end end diff --git a/test/vool/class_send/helper.rb b/test/vool/class_send/helper.rb index 3775f127..b303ac62 100644 --- a/test/vool/class_send/helper.rb +++ b/test/vool/class_send/helper.rb @@ -4,12 +4,13 @@ module Vool # relies on @ins and receiver_type method module ClassHarness - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - Risc::Builtin.boot_functions - @ins = compile_first_method( send_method ) + Risc.boot! + @compiler = compile_first_method( send_method ) + @ins = @compiler.mom_instructions.next end def test_first_not_array @@ -19,7 +20,7 @@ module Vool assert_equal Mom::MessageSetup , @ins.class , @ins end def test_two_instructions_are_returned - assert_equal 3 , @ins.length , @ins + assert_equal 6 , @ins.length , @ins end def test_receiver_move_class assert_equal Mom::ArgumentTransfer, @ins.next(1).class @@ -37,7 +38,8 @@ module Vool assert_equal Parfait::CallableMethod, @ins.next(2).method.class end def test_array - check_array [Mom::MessageSetup,Mom::ArgumentTransfer,Mom::SimpleCall] , @ins + check_array [MessageSetup,ArgumentTransfer,SimpleCall,Label, + ReturnSequence , Label] , @ins end end diff --git a/test/vool/class_send/test_class_def.rb b/test/vool/class_send/test_class_def.rb index f75139c0..00d4056f 100644 --- a/test/vool/class_send/test_class_def.rb +++ b/test/vool/class_send/test_class_def.rb @@ -17,16 +17,8 @@ module Vool end def setup - statements = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_vool(class_main) - assert_equal Vool::ClassStatement, statements.class - ret = statements.to_mom(nil) - assert_equal Parfait::Class , statements.clazz.class , statements - @method = statements.clazz.get_method(:main) - assert_equal Parfait::VoolMethod , @method.class - assert_equal Mom::MomCompiler , ret.class - compiler = ret.method_compilers.find{|c| c.get_method.name == :main } - assert_equal Risc::MethodCompiler , compiler.class - @ins = @method.source.to_mom( compiler ) + ret = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(class_main) + @ins = ret.compilers.first.mom_instructions.next end def test_any @@ -35,7 +27,7 @@ module Vool def test_no_arg assert_equal Mom::ArgumentTransfer, @ins.next(1).class - assert_equal 0, @ins.next(1).arguments.length + assert_equal 1, @ins.next(1).arguments.length end def test_call_two assert_equal SimpleCall, @ins.next(2).class diff --git a/test/vool/class_send/test_harness.rb b/test/vool/class_send/test_harness.rb index d12f52c7..11527c37 100644 --- a/test/vool/class_send/test_harness.rb +++ b/test/vool/class_send/test_harness.rb @@ -2,7 +2,6 @@ require_relative "helper" module Vool class ClassSendHarness < MiniTest::Test - include MomCompile include ClassHarness def send_method diff --git a/test/vool/class_send/test_send_class.rb b/test/vool/class_send/test_send_class.rb index fef6aa62..fcf6318f 100644 --- a/test/vool/class_send/test_send_class.rb +++ b/test/vool/class_send/test_send_class.rb @@ -3,7 +3,6 @@ require_relative "helper" module Vool class TestSendClassMom < MiniTest::Test include ClassHarness - include Mom def send_method "Object.get_internal_word(0)" diff --git a/test/vool/send/helper.rb b/test/vool/send/helper.rb index bc89eb83..1f860562 100644 --- a/test/vool/send/helper.rb +++ b/test/vool/send/helper.rb @@ -3,28 +3,30 @@ require_relative "../helper" module Vool # relies on @ins and receiver_type method module SimpleSendHarness - include MomCompile + include VoolCompile + include Mom def setup Parfait.boot!(Parfait.default_test_options) - Risc::Builtin.boot_functions - @ins = compile_first_method( send_method ) + Mom.boot! + @compiler = compile_first_method( send_method ) + @ins = @compiler.mom_instructions.next end def test_first_not_array assert Array != @ins.class , @ins end def test_class_compiles - assert_equal Mom::MessageSetup , @ins.class , @ins + assert_equal MessageSetup , @ins.class , @ins end def test_two_instructions_are_returned - assert_equal 3 , @ins.length , @ins + assert_equal 6 , @ins.length , @ins end def test_receiver_move_class - assert_equal Mom::ArgumentTransfer, @ins.next(1).class + assert_equal ArgumentTransfer, @ins.next(1).class end def test_receiver_move - assert_equal Mom::SlotDefinition, @ins.next.receiver.class + assert_equal SlotDefinition, @ins.next.receiver.class end def test_receiver type , value = receiver @@ -32,13 +34,14 @@ module Vool assert_equal value, @ins.next.receiver.known_object.value end def test_call_is - assert_equal Mom::SimpleCall, @ins.next(2).class + assert_equal SimpleCall, @ins.next(2).class end def test_call_has_method assert_equal Parfait::CallableMethod, @ins.next(2).method.class end def test_array - check_array [Mom::MessageSetup,Mom::ArgumentTransfer,Mom::SimpleCall] , @ins + check_array [MessageSetup,ArgumentTransfer,SimpleCall,Label, ReturnSequence , + Label] , @ins end end end diff --git a/test/vool/send/test_send_args_send.rb b/test/vool/send/test_send_args_send.rb index fec22686..de04c079 100644 --- a/test/vool/send/test_send_args_send.rb +++ b/test/vool/send/test_send_args_send.rb @@ -2,18 +2,19 @@ require_relative "helper" module Vool class TestSendArgsSendMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) Risc.boot! - @ins = compile_first_method( "a = main(1 + 2)" ) + @compiler = compile_first_method( "a = main(1 + 2)" ) + @ins = @compiler.mom_instructions.next end def test_array check_array [MessageSetup, ArgumentTransfer, SimpleCall, SlotLoad, MessageSetup , - ArgumentTransfer, SimpleCall, SlotLoad] , @ins + ArgumentTransfer, SimpleCall, SlotLoad ,Label, ReturnSequence , + Label] , @ins end def test_one_call diff --git a/test/vool/send/test_send_cached_simple.rb b/test/vool/send/test_send_cached_simple.rb index 2e942f80..7e9f4318 100644 --- a/test/vool/send/test_send_cached_simple.rb +++ b/test/vool/send/test_send_cached_simple.rb @@ -2,12 +2,12 @@ require_relative "../helper" module Vool class TestSendCachedSimpleMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "a = 5; a.div4") + @compiler = compile_first_method( "a = 5; a.div4") + @ins = @compiler.mom_instructions.next end def test_check_type assert_equal NotSameCheck , @ins.next.class , @ins @@ -23,12 +23,13 @@ module Vool assert_equal ResolveMethod , @ins.next(3).class , @ins end def test_dynamic_call_last - assert_equal DynamicCall , @ins.last.class , @ins + assert_equal DynamicCall , @ins.next(7).class , @ins end def test_array check_array [SlotLoad, NotSameCheck, SlotLoad, ResolveMethod, Label, MessageSetup , - ArgumentTransfer, DynamicCall] , @ins + ArgumentTransfer, DynamicCall, Label, ReturnSequence , + Label] , @ins end end diff --git a/test/vool/send/test_send_self.rb b/test/vool/send/test_send_self.rb index 8d782a23..89134a52 100644 --- a/test/vool/send/test_send_self.rb +++ b/test/vool/send/test_send_self.rb @@ -3,7 +3,6 @@ require_relative "helper" module Vool class TestSendSelfMom < MiniTest::Test include SimpleSendHarness - include Mom def send_method "self.get_internal_word(0)" diff --git a/test/vool/send/test_send_simple_args.rb b/test/vool/send/test_send_simple_args.rb index 948c6bac..4b32aa23 100644 --- a/test/vool/send/test_send_simple_args.rb +++ b/test/vool/send/test_send_simple_args.rb @@ -20,7 +20,8 @@ module Vool assert_equal 2, @ins.next(1).arguments[1].right.known_object.value end def test_array - check_array [Mom::MessageSetup,Mom::ArgumentTransfer,Mom::SimpleCall] , @ins + check_array [MessageSetup,ArgumentTransfer,SimpleCall, Label, ReturnSequence , + Label] , @ins end end end diff --git a/test/vool/test_assign.rb b/test/vool/test_assign.rb index 0e942026..9e556c63 100644 --- a/test/vool/test_assign.rb +++ b/test/vool/test_assign.rb @@ -2,11 +2,12 @@ require_relative "helper" module Vool class TestAssignMom < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "local = 5") + @compiler = compile_first_method( "local = 5") + @ins = @compiler.mom_instructions.next end def test_class_compiles @@ -34,10 +35,11 @@ module Vool #otherwise as above, but assigning instance, so should get a SlotLoad class TestAssignMomInstanceToLocal < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "@a = 5 ; local = @a") + @compiler = compile_first_method( "@a = 5 ; local = @a") + @ins = @compiler.mom_instructions.next end def test_class_compiles assert_equal Mom::SlotLoad , @ins.next.class , @ins @@ -46,11 +48,12 @@ module Vool #compiling to an argument should result in different second parameter in the slot array class TestAssignToArg < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "arg = 5") + @compiler = compile_first_method( "arg = 5") + @ins = @compiler.mom_instructions.next end def test_class_compiles @@ -71,17 +74,19 @@ module Vool end class TestAssignMomToInstance < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) end def test_assigns_const - @ins = compile_first_method( "@a = 5") + @compiler = compile_first_method( "@a = 5") + @ins = @compiler.mom_instructions.next assert_equal Mom::SlotLoad , @ins.class , @ins assert_equal Mom::IntegerConstant , @ins.right.known_object.class , @ins end def test_assigns_move - @ins = compile_first_method( "@a = arg") + @compiler = compile_first_method( "@a = arg") + @ins = @compiler.mom_instructions.next assert_equal Mom::SlotLoad , @ins.class , @ins assert_equal Mom::SlotDefinition , @ins.right.class , @ins end diff --git a/test/vool/test_class_statement.rb b/test/vool/test_class_statement.rb new file mode 100644 index 00000000..4f67616f --- /dev/null +++ b/test/vool/test_class_statement.rb @@ -0,0 +1,55 @@ + +require_relative "helper" + +module Vool + class TestClassStatement < MiniTest::Test + include ScopeHelper + def setup + Parfait.boot!({}) + ruby_tree = Ruby::RubyCompiler.compile( as_test_main("a = 5") ) + @vool = ruby_tree.to_vool + end + def test_class + assert_equal ClassStatement , @vool.class + end + def test_method + assert_equal MethodStatement , @vool.body.first.class + end + def test_create_class + assert_equal Parfait::Class , @vool.create_class_object.class + end + def test_create_class + assert_equal :Test , @vool.create_class_object.name + end + end + class TestClassStatementCompile < MiniTest::Test + include VoolCompile + + def setup + @compiler = compile_first_method( "if(@a) ; @a = 5 ; else; @a = 6 ; end") + @ins = @compiler.mom_instructions + end + + def test_label + assert_equal Label , @ins.class , @ins + assert_equal "Test_Type.main" , @ins.name , @ins + end + def test_condition_compiles_to_check + assert_equal TruthCheck , @ins.next.class , @ins + end + def test_condition_is_slot + assert_equal SlotDefinition , @ins.next.condition.class , @ins + end + def test_label_after_check + assert_equal Label , @ins.next(2).class , @ins + end + def test_label_last + assert_equal Label , @ins.last.class , @ins + end + def test_array + check_array [Label, TruthCheck, Label, SlotLoad, Jump , + Label, SlotLoad, Label, Label, ReturnSequence , + Label] , @ins + end + end +end diff --git a/test/vool/test_if_condition.rb b/test/vool/test_if_condition.rb index 71d12c8d..d4b659ff 100644 --- a/test/vool/test_if_condition.rb +++ b/test/vool/test_if_condition.rb @@ -2,13 +2,12 @@ require_relative "helper" module Vool class TestConditionIfMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - Risc::Builtin.boot_functions - @ins = compile_first_method( "if(5.div4) ; @a = 6 ; else; @a = 5 ; end") + @compiler = compile_first_method( "if(5.div4) ; @a = 6 ; else; @a = 5 ; end") + @ins = @compiler.mom_instructions.next end def test_condition @@ -22,8 +21,9 @@ module Vool assert_equal :div4 , @ins.next(2).method.name end def test_array - check_array [MessageSetup, ArgumentTransfer, SimpleCall, SlotLoad, TruthCheck, Label , - SlotLoad, Jump, Label, SlotLoad, Label] , @ins + check_array [MessageSetup, ArgumentTransfer, SimpleCall, SlotLoad, TruthCheck, + Label ,SlotLoad, Jump, Label, SlotLoad, Label, + Label, ReturnSequence, Label ] , @ins end end diff --git a/test/vool/test_if_no_else.rb b/test/vool/test_if_no_else.rb index 6a47ec7a..166e5948 100644 --- a/test/vool/test_if_no_else.rb +++ b/test/vool/test_if_no_else.rb @@ -3,12 +3,12 @@ require_relative "helper" module Vool class TestIfNoElse < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "if(@a) ; @a = 5 ; end") + @compiler = compile_first_method( "if(@a) ; @a = 5 ; end") + @ins = @compiler.mom_instructions.next end def test_condition_compiles_to_check @@ -24,7 +24,8 @@ module Vool assert_equal Label , @ins.last.class , @ins end def test_array - check_array [TruthCheck, Label, SlotLoad, Label], @ins + check_array [TruthCheck, Label, SlotLoad, Label, Label , + ReturnSequence, Label], @ins end end end diff --git a/test/vool/test_if_simple.rb b/test/vool/test_if_simple.rb index c4db5392..6c2ce472 100644 --- a/test/vool/test_if_simple.rb +++ b/test/vool/test_if_simple.rb @@ -3,12 +3,12 @@ require_relative "helper" module Vool class TestSimpleIfMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "if(@a) ; @a = 5 ; else; @a = 6 ; end") + @compiler = compile_first_method( "if(@a) ; @a = 5 ; else; @a = 6 ; end") + @ins = @compiler.mom_instructions.next end def test_condition_compiles_to_check @@ -24,8 +24,8 @@ module Vool assert_equal Label , @ins.last.class , @ins end def test_array - check_array [TruthCheck, Label, SlotLoad, Jump, Label, SlotLoad , - Label] , @ins + check_array [TruthCheck, Label, SlotLoad, Jump, Label , + SlotLoad, Label, Label, ReturnSequence, Label], @ins end end end diff --git a/test/vool/test_ivar.rb b/test/vool/test_ivar.rb index 9dd2d159..63818ecb 100644 --- a/test/vool/test_ivar.rb +++ b/test/vool/test_ivar.rb @@ -2,11 +2,12 @@ require_relative "helper" module Vool class TestIvarMom < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "@a = 5") + @compiler = compile_first_method( "@a = 5") + @ins = @compiler.mom_instructions.next end def test_compiles_not_array diff --git a/test/vool/test_local_assignment.rb b/test/vool/test_local_assignment.rb index 7f526014..4df953f9 100644 --- a/test/vool/test_local_assignment.rb +++ b/test/vool/test_local_assignment.rb @@ -2,11 +2,12 @@ require_relative "helper" module Vool class TestLocalMom < MiniTest::Test - include MomCompile + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "a = 5") + @compiler = compile_first_method( "a = 5") + @ins = @compiler.mom_instructions.next end def test_compiles_not_array diff --git a/test/vool/test_method_statement.rb b/test/vool/test_method_statement.rb new file mode 100644 index 00000000..dcbf7813 --- /dev/null +++ b/test/vool/test_method_statement.rb @@ -0,0 +1,29 @@ +require_relative "helper" + +module Vool + class TestMethodStatement < MiniTest::Test + include VoolCompile + + def setup + Parfait.boot!(Parfait.default_test_options) + ruby_tree = Ruby::RubyCompiler.compile( as_test_main("a = 5") ) + @clazz = ruby_tree.to_vool + end + def method + @clazz.body.first + end + def test_setup + assert_equal ClassStatement , @clazz.class + assert_equal Statements , @clazz.body.class + assert_equal MethodStatement , method.class + end + def test_class + assert_equal Parfait::Class , @clazz.create_class_object.class + end + def test_method + clazz = @clazz.create_class_object + assert_equal Parfait::VoolMethod , method.make_method(clazz).class + end + + end +end diff --git a/test/vool/test_return.rb b/test/vool/test_return.rb index 89c9d39e..8b15a158 100644 --- a/test/vool/test_return.rb +++ b/test/vool/test_return.rb @@ -2,57 +2,57 @@ require_relative "helper" module Vool class TestReturnMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @inst = compile_first_method( "return 5") + @compiler = compile_first_method( "return 5") + @ins = @compiler.mom_instructions.next end def test_class_compiles - assert_equal SlotLoad , @inst.class , @inst + assert_equal SlotLoad , @ins.class , @ins end def test_slot_is_set - assert @inst.left + assert @ins.left end def test_two_instructions_are_returned - assert_equal 2 , @inst.length - end - def test_second_is_return - assert_equal ReturnJump, @inst.last.class + assert_equal 5 , @ins.length end def test_slot_starts_at_message - assert_equal :message , @inst.left.known_object + assert_equal :message , @ins.left.known_object end def test_slot_gets_return - assert_equal :return_value , @inst.left.slots[0] + assert_equal :return_value , @ins.left.slots[0] end def test_slot_assigns_something - assert @inst.right + assert @ins.right end def test_slot_assigns_int - assert_equal Mom::IntegerConstant , @inst.right.known_object.class + assert_equal Mom::IntegerConstant , @ins.right.known_object.class + end + def test_second_is_return + assert_equal ReturnJump, @ins.next(1).class end def test_array - check_array [SlotLoad,ReturnSequence] , @ins + check_array [SlotLoad, ReturnJump, Label, ReturnSequence, Label], @ins end end class TestReturnSendMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - Risc.boot! - @ins = compile_first_method( "return 5.div4") + @compiler = compile_first_method( "return 5.div4") + @ins = @compiler.mom_instructions.next end def test_return_is_last - assert_equal ReturnJump , @ins.last.class + assert_equal ReturnJump , @ins.next(5).class end def test_array - check_array [MessageSetup,ArgumentTransfer,SimpleCall,SlotLoad,SlotLoad,ReturnJump] , @ins + check_array [MessageSetup,ArgumentTransfer,SimpleCall,SlotLoad, + SlotLoad,ReturnJump, Label, ReturnSequence, Label] , @ins end end end diff --git a/test/vool/test_while_simple.rb b/test/vool/test_while_statement.rb similarity index 65% rename from test/vool/test_while_simple.rb rename to test/vool/test_while_statement.rb index 34d649b3..761ff735 100644 --- a/test/vool/test_while_simple.rb +++ b/test/vool/test_while_statement.rb @@ -2,12 +2,12 @@ require_relative "helper" module Vool class TestSimpleWhileMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "while(@a) ; @a = 5 ; end") + @compiler = compile_first_method( "while(@a) ; @a = 5 ; end") + @ins = @compiler.mom_instructions.next end def test_compiles_as_while @@ -20,7 +20,8 @@ module Vool assert_equal SlotDefinition , @ins.next.condition.class , @ins end def test_array - check_array [Label, TruthCheck, SlotLoad, Jump, Label], @ins + check_array [Label, TruthCheck, SlotLoad, Jump, Label , + Label, ReturnSequence, Label], @ins end end end diff --git a/test/vool/test_while_condition.rb b/test/vool/test_while_statement1.rb similarity index 81% rename from test/vool/test_while_condition.rb rename to test/vool/test_while_statement1.rb index 06066eb0..30699de8 100644 --- a/test/vool/test_while_condition.rb +++ b/test/vool/test_while_statement1.rb @@ -3,13 +3,12 @@ require_relative "helper" module Vool class TestWhileConditionMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile def setup Parfait.boot!(Parfait.default_test_options) - Risc::Builtin.boot_functions - @ins = compile_first_method( "while(5.div4) ; 5.div4 ; end") + @compiler = compile_first_method( "while(5.div4) ; 5.div4 ; end") + @ins = @compiler.mom_instructions.next end def test_condition_compiles_to_check @@ -31,7 +30,7 @@ module Vool def test_array check_array [Label, MessageSetup, ArgumentTransfer, SimpleCall, SlotLoad , TruthCheck, MessageSetup, ArgumentTransfer, SimpleCall, Jump , - Label] , @ins + Label, Label, ReturnSequence, Label] , @ins end end diff --git a/test/vool/test_yield_statement.rb b/test/vool/test_yield_statement.rb index 209be194..17fb22e2 100644 --- a/test/vool/test_yield_statement.rb +++ b/test/vool/test_yield_statement.rb @@ -55,17 +55,19 @@ module Vool end end class TestYieldArgsSendMom < MiniTest::Test - include MomCompile + include VoolCompile include YieldBasics def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "return yield(1)" ) + @compiler = compile_first_method( "return yield(1)" ) + @ins = @compiler.mom_instructions.next end def test_array check_array [NotSameCheck, Label, MessageSetup, ArgumentTransfer, BlockYield , - SlotLoad, SlotLoad, ReturnJump] , @ins + SlotLoad, SlotLoad, ReturnJump, Label, ReturnSequence , + Label] , @ins end def test_transfer assert_equal ArgumentTransfer, @ins.next(3).class @@ -79,16 +81,17 @@ module Vool end end class TestYieldNoArgsSendMom < MiniTest::Test - include MomCompile - include Mom + include VoolCompile include YieldBasics def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_method( "return yield" ) + @compiler = compile_first_method( "return yield" ) + @ins = @compiler.mom_instructions.next end def test_array check_array [NotSameCheck, Label, MessageSetup, ArgumentTransfer, BlockYield , - SlotLoad, SlotLoad, ReturnJump] , @ins + SlotLoad, SlotLoad, ReturnJump, Label, ReturnSequence , + Label] , @ins end def test_transfer assert_equal ArgumentTransfer, @ins.next(3).class