diff --git a/lib/parfait.rb b/lib/parfait.rb index 167945d3..456e68e5 100644 --- a/lib/parfait.rb +++ b/lib/parfait.rb @@ -13,6 +13,3 @@ require "parfait/layout" require "parfait/message" require "parfait/frame" require "parfait/space" - -#if we are in the ruby run-time / generating an executable -require "virtual/parfait_adapter" diff --git a/lib/parfait/module.rb b/lib/parfait/module.rb index d2a9cf7c..1e4aadec 100644 --- a/lib/parfait/module.rb +++ b/lib/parfait/module.rb @@ -30,9 +30,17 @@ module Parfait @instance_methods end + def method_names + names = List.new + @instance_methods.each do |method| + names.push method.name + end + names + end + def add_instance_method method raise "not a method #{method.class} #{method.inspect}" unless method.is_a? Method - raise "syserr #{method.name.class}" unless method.name.is_a? Word + raise "syserr #{method.name.class}" unless method.name.is_a? Symbol found = get_instance_method( method.name ) if found @instance_methods.delete(found) @@ -48,6 +56,7 @@ module Parfait end def create_instance_method name , arg_names + raise "uups #{name}.#{name.class}" unless name.is_a?(Symbol) clazz = Space.object_space.get_class_by_name(self.name) raise "??? #{self.name}" unless clazz Method.new_object( clazz , name , arg_names ) @@ -61,7 +70,7 @@ module Parfait end def get_instance_method fname - raise "uups #{fname}.#{fname.class}" unless fname.is_a?(Word) or fname.is_a?(String) + raise "uups #{fname}.#{fname.class}" unless fname.is_a?(Symbol) #if we had a hash this would be easier. Detect or find would help too @instance_methods.each do |m| return m if(m.name == fname ) @@ -71,7 +80,7 @@ module Parfait # get the method and if not found, try superclasses. raise error if not found def resolve_method m_name - raise "uups #{m_name}.#{m_name.class}" unless m_name.is_a?(Word) or m_name.is_a?(String) + raise "uups #{m_name}.#{m_name.class}" unless m_name.is_a?(Symbol) method = get_instance_method(m_name) return method if method if( @super_class ) diff --git a/lib/parfait/space.rb b/lib/parfait/space.rb index c9936da1..70a2ab62 100644 --- a/lib/parfait/space.rb +++ b/lib/parfait/space.rb @@ -56,14 +56,14 @@ module Parfait end def get_main - kernel = get_class_by_name "Object" - kernel.get_instance_method "main" + kernel = get_class_by_name :Object + kernel.get_instance_method :main end # this is the way to instantiate classes (not Parfait::Class.new) # so we get and keep exactly one per name def get_class_by_name name - raise "uups #{name}.#{name.class}" unless name.is_a?(Word) or name.is_a?(String) + raise "uups #{name}.#{name.class}" unless name.is_a?(Symbol) c = @classes[name] puts "MISS, no class #{name} #{name.class}" unless c # " #{@classes}" c diff --git a/lib/register/builtin/integer.rb b/lib/register/builtin/integer.rb index 23585c7e..17a4a380 100644 --- a/lib/register/builtin/integer.rb +++ b/lib/register/builtin/integer.rb @@ -9,7 +9,7 @@ module Builtin # As we write before we recurse (save a push) we write the number backwards # arguments: string address , integer def utoa context - utoa_function = Virtual::CompiledMethodInfo.create_method("Integer" ,"utoa" , [ Virtual::Integer ] ) + utoa_function = Virtual::CompiledMethodInfo.create_method(:Integer ,:utoa , [ Virtual::Integer ] ) function.info.return_type = Virtual::Integer function.info.receiver = Virtual::Integer return utoa_function @@ -29,7 +29,7 @@ module Builtin end def putint context - putint_function = Virtual::CompiledMethodInfo.create_method("Integer","putint" , [] ) + putint_function = Virtual::CompiledMethodInfo.create_method(:Integer,:putint , [] ) putint_function.info.return_type = Virtual::Integer putint_function.info.receiver = Virtual::Integer return putint_function @@ -58,7 +58,7 @@ module Builtin # a hand coded version of the fibonachi numbers # not my hand off course, found in the net http://www.peter-cockerell.net/aalp/html/ch-5.html def fibo context - fibo_function = Virtual::CompiledMethodInfo.create_method("Integer","fibo" , [] ) + fibo_function = Virtual::CompiledMethodInfo.create_method(:Integer,:fibo , [] ) fibo_function.info.return_type = Virtual::Integer fibo_function.info.receiver = Virtual::Integer return fibo_function diff --git a/lib/register/builtin/kernel.rb b/lib/register/builtin/kernel.rb index a5d3884f..ede7333f 100644 --- a/lib/register/builtin/kernel.rb +++ b/lib/register/builtin/kernel.rb @@ -5,7 +5,7 @@ module Builtin # 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 (and relocation) def __init__ context - function = Virtual::CompiledMethodInfo.create_method("Kernel","__init__" , []) + function = Virtual::CompiledMethodInfo.create_method(:Kernel,:__init__ , []) # puts "INIT LAYOUT #{function.get_layout.get_layout}" function.info.return_type = Virtual::Integer main = Virtual::Machine.instance.space.get_main @@ -16,14 +16,14 @@ module Builtin return function end def putstring context - function = Virtual::CompiledMethodInfo.create_method("Kernel" , "putstring" , [] ) + function = Virtual::CompiledMethodInfo.create_method(:Kernel , :putstring , [] ) return function ret = Virtual::RegisterMachine.instance.write_stdout(function) function.set_return ret function end def exit context - function = Virtual::CompiledMethodInfo.create_method("Kernel","exit" , []) + function = Virtual::CompiledMethodInfo.create_method(:Kernel,:exit , []) function.info.return_type = Virtual::Integer return function ret = Virtual::RegisterMachine.instance.exit(function) @@ -31,7 +31,7 @@ module Builtin function end def __send context - function = Virtual::CompiledMethodInfo.create_method("Kernel" ,"__send" , [] ) + function = Virtual::CompiledMethodInfo.create_method(:Kernel ,:__send , [] ) function.info.return_type = Virtual::Integer return function end diff --git a/lib/register/builtin/object.rb b/lib/register/builtin/object.rb index a4b296e2..9d1166f0 100644 --- a/lib/register/builtin/object.rb +++ b/lib/register/builtin/object.rb @@ -5,7 +5,7 @@ module Builtin # main entry point, ie __init__ calls this # defined here as empty, to be redefined def main context - function = Virtual::CompiledMethodInfo.create_method("Object","main" , []) + function = Virtual::CompiledMethodInfo.create_method(:Object,:main , []) return function end @@ -17,7 +17,7 @@ module Builtin # The at_index is just "below" the api, something we need but don't want to expose, # so we can't code the above in ruby def _get_instance_variable context , name = Virtual::Integer - get_function = Virtual::CompiledMethodInfo.create_method("Object","_get_instance_variable" , [ Virtual::Reference ] ) + get_function = Virtual::CompiledMethodInfo.create_method(:Object,:_get_instance_variable , [ Virtual::Reference ] ) return get_function me = get_function.receiver var_name = get_function.args.first @@ -38,7 +38,7 @@ module Builtin end def _set_instance_variable(context , name = Virtual::Integer , value = Virtual::Integer ) - set_function = Virtual::CompiledMethodInfo.create_method("Object","_set_instance_variable" ,[Virtual::Reference ,Virtual::Reference] ) + set_function = Virtual::CompiledMethodInfo.create_method(:Object,:_set_instance_variable ,[Virtual::Reference ,Virtual::Reference] ) return set_function receiver set_function me = set_function.receiver diff --git a/lib/virtual.rb b/lib/virtual.rb index 8dee2e1e..27673f04 100644 --- a/lib/virtual.rb +++ b/lib/virtual.rb @@ -1,5 +1,8 @@ require "parfait" require "virtual/machine" +#if we are in the ruby run-time / generating an executable +require "virtual/positioned" +require "virtual/parfait_adapter" require "virtual/compiler" require "virtual/instruction" diff --git a/lib/virtual/boot.rb b/lib/virtual/boot.rb index 3bcaeaf6..f23cec87 100644 --- a/lib/virtual/boot.rb +++ b/lib/virtual/boot.rb @@ -21,23 +21,23 @@ module Virtual # map from the vm - class_name to the Parfait class (which carries parfait name) class_mappings = {} #will later become instance variable - values = [ "Value" , "Integer" , "Kernel" , "Object"].collect {|cl| Virtual.new_word(cl) } + values = [ :Value , :Integer , :Kernel , :Object] value_classes = values.collect { |cl| @space.create_class(cl,nil) } - layouts = { "Word" => [] , - "List" => [] , - "Message" => [], - "MetaClass" => [], - "BinaryCode" => [], - "Space" => ["classes","frames","messages","next_message","next_frame"], - "Frame" => ["locals" , "tmps" ], - "Layout" => ["object_class"] , - "Class" => ["object_layout"], - "Dictionary" => ["keys" , "values"] , - "Method" => ["name" , "code" ,"arg_names" , "locals" , "tmps"] , - "Module" => ["name" , "instance_methods", "super_class", "meta_class"] + layouts = { :Word => [] , + :List => [] , + :Message => [], + :MetaClass => [], + :BinaryCode => [], + :Space => [:classes ,:frames ,:messages ,:next_message ,:next_frame], + :Frame => [:locals , :tmps ], + :Layout => [:object_class] , + :Class => [:object_layout ], + :Dictionary => [:keys , :values ] , + :Method => [:name , :code ,:arg_names , :locals , :tmps ] , + :Module => [:name , :instance_methods , :super_class , :meta_class ] } layouts.each do |name , layout| - class_mappings[name] = @space.create_class(Virtual.new_word(name) , nil) + class_mappings[name] = @space.create_class(name , nil) end value_classes[1].set_super_class( value_classes[0] ) # #set superclass (value) for integer value_classes[2].set_super_class( value_classes[0] ) # and kernel (TODO is module) @@ -49,11 +49,11 @@ module Virtual class_mappings.each do |name , clazz| variables = layouts[name] variables.each do |var_name| - clazz.object_layout.add_instance_variable Virtual.new_word(var_name) + clazz.object_layout.add_instance_variable var_name end end # superclass and layout corrections - supers = { "BinaryCode" => "Word", "Layout" => "List", "Class" => "Module"} + supers = { :BinaryCode => :Word , :Layout => :List , :Class => :Module } supers.each do |classname , superclass_name| clazz = class_mappings[classname] super_class = class_mappings[superclass_name] @@ -70,9 +70,9 @@ module Virtual # lookup half created class info # but it must be done before going through the objects (next step) @class_mappings = class_mappings - class_mappings["Integer"] = value_classes[1] #need for further booting - class_mappings["Kernel"] = value_classes[2] #need for further booting - class_mappings["Object"] = value_classes[3] #need for further booting + class_mappings[:Integer ] = value_classes[1] #need for further booting + class_mappings[:Kernel ] = value_classes[2] #need for further booting + class_mappings[:Object ] = value_classes[3] #need for further booting @space.late_init @@ -96,25 +96,25 @@ module Virtual def boot_functions! # very fiddly chicken 'n egg problem. Functions need to be in the right order, and in fact we # have to define some dummies, just for the other to compile - # TODO: go through the virtual parfait layer and adjust function names to what they really are - obj = @class_mappings["Object"] + # TODO go through the virtual parfait layer and adjust function names to what they really are + obj = @class_mappings[:Object ] [:main , :_get_instance_variable , :_set_instance_variable].each do |f| obj.add_instance_method Builtin::Object.send(f , nil) end - obj = @class_mappings["Kernel"] + obj = @class_mappings[:Kernel ] # create dummy main first, __init__ calls it [:putstring,:exit,:__send ].each do |f| obj.add_instance_method Builtin::Kernel.send(f , nil) end underscore_init = obj.add_instance_method Builtin::Kernel.send(:__init__, nil) - obj = @class_mappings["Integer"] + obj = @class_mappings[:Integer ] [:putint,:fibo].each do |f| obj.add_instance_method Builtin::Integer.send(f , nil) end # and the @init block in turn _jumps_ to __init__ - # the point of which is that by the time main executes, all is "normal" + # the point of which is that by the time main executes, all is :normal: @init = Block.new(:_init_ , nil ) @init.add_code(Register::RegisterMain.new(underscore_init)) end diff --git a/lib/virtual/compiled_method_info.rb b/lib/virtual/compiled_method_info.rb index cfc1361b..4b095de6 100644 --- a/lib/virtual/compiled_method_info.rb +++ b/lib/virtual/compiled_method_info.rb @@ -35,10 +35,8 @@ module Virtual # # compile code then works with the method, but adds code tot the info def self.create_method( class_name , method_name , args) - raise "uups #{class_name}.#{class_name.class}" if class_name.is_a? Symbol - raise "uups #{method_name}.#{method_name.class}" if class_name.is_a? Symbol - class_name = Virtual.new_word(class_name) if class_name.is_a? String - method_name = Virtual.new_word(method_name) if method_name.is_a? String + raise "uups #{class_name}.#{class_name.class}" unless class_name.is_a? Symbol + raise "uups #{method_name}.#{method_name.class}" unless class_name.is_a? Symbol clazz = Machine.instance.space.get_class_by_name class_name raise "No such class #{class_name}" unless clazz method = clazz.create_instance_method( method_name , Virtual.new_list(args)) diff --git a/lib/virtual/compiler/basic_expressions.rb b/lib/virtual/compiler/basic_expressions.rb index 06421983..27819f7e 100644 --- a/lib/virtual/compiler/basic_expressions.rb +++ b/lib/virtual/compiler/basic_expressions.rb @@ -46,7 +46,7 @@ module Virtual # whichever way this goes the result is stored in the return slot (as all compiles) def self.compile_name expression , method return Self.new( Reference.new(method.for_class)) if expression.name == :self - name = Virtual.new_word expression.name.to_s + name = expression.name.to_sym if method.has_var(name) # either an argument, so it's stored in message if( index = method.has_arg(name)) @@ -71,7 +71,7 @@ module Virtual # attr_reader :string def self.compile_string expression , method - value = Virtual.new_word(expression.string) + value = expression.string.to_sym to = Return.new(Reference , value) method.info.add_code Set.new( to , value ) to @@ -84,11 +84,11 @@ module Virtual end r = Compiler.compile(expression.right , method ) raise "oh noo, nil from where #{expression.right.inspect}" unless r - index = method.has_arg(Virtual.new_word name) + index = method.has_arg(name) if index method.info.add_code Set.new(Return.new , MessageSlot.new(index , r,type , r )) else - index = method.ensure_local(Virtual.new_word expression.left.name) + index = method.ensure_local(expression.left.name.to_sym) method.info.add_code Set.new(Return.new , FrameSlot.new(index , r.type , r )) end r diff --git a/lib/virtual/compiler/callsite_expression.rb b/lib/virtual/compiler/callsite_expression.rb index c2aa984e..023e0df0 100644 --- a/lib/virtual/compiler/callsite_expression.rb +++ b/lib/virtual/compiler/callsite_expression.rb @@ -8,7 +8,7 @@ module Virtual me = Compiler.compile( expession.receiver , method ) method.info.add_code NewMessage.new method.info.add_code Set.new(NewSelf.new(me.type), me) - method.info.add_code Set.new(NewName.new(), Virtual.new_word(expession.name)) + method.info.add_code Set.new(NewName.new(), expession.name.to_sym) compiled_args = [] expession.args.each_with_index do |arg , i| #compile in the running method, ie before passing control diff --git a/lib/virtual/instruction.rb b/lib/virtual/instruction.rb index 0e76e17a..982487ba 100644 --- a/lib/virtual/instruction.rb +++ b/lib/virtual/instruction.rb @@ -1,4 +1,3 @@ -require_relative "positioned" module Virtual diff --git a/lib/virtual/instructions/set.rb b/lib/virtual/instructions/set.rb index 65d2f24b..955610ce 100644 --- a/lib/virtual/instructions/set.rb +++ b/lib/virtual/instructions/set.rb @@ -7,8 +7,6 @@ module Virtual class Set < Instruction def initialize to , from @to = to - # hard to find afterwards where it came from, so ensure it doesn't happen - raise "From must be slot or constant, not symbol #{from}" if from.is_a? Symbol @from = from end attr_reader :from , :to diff --git a/lib/virtual/parfait_adapter.rb b/lib/virtual/parfait_adapter.rb index fa35cd98..4fce8479 100644 --- a/lib/virtual/parfait_adapter.rb +++ b/lib/virtual/parfait_adapter.rb @@ -16,7 +16,7 @@ module FakeMem end end def init_layout - vm_name = self.class.name.split("::").last + vm_name = self.class.name.split("::").last.to_sym clazz = Virtual::Machine.instance.class_mappings[vm_name] raise "Class not found #{vm_name}" unless clazz raise "Layout not set #{vm_name}" unless clazz.object_layout @@ -52,6 +52,28 @@ module FakeMem padded(words*4) # 4 == word length, a constant waiting for a home end end +module Virtual + def self.new_list array + list = Parfait::List.new_object + list.set_length array.length + index = 1 + while index <= array.length do + list.set(index , array[index - 1]) + index = index + 1 + end + list + end +end +class Symbol + include Positioned + def init_layout; end + def has_layout? + true + end + def get_layout + Virtual::Machine.instance.class_mappings[:Word].object_layout + end +end module Parfait # Objects memory functions. Object memory is 1 based @@ -158,26 +180,3 @@ module Parfait end end end - - -module Virtual - # Functions to generate parfait objects - def self.new_word( string ) - string = string.to_s if string.is_a? Symbol - word = Parfait::Word.new_object( string.length ) - string.codepoints.each_with_index do |code , index | - word.set_char(index + 1 , code) - end - word - end - def self.new_list array - list = Parfait::List.new_object - list.set_length array.length - index = 1 - while index <= array.length do - list.set(index , array[index - 1]) - index = index + 1 - end - list - end -end diff --git a/lib/virtual/passes/minimizer.rb b/lib/virtual/passes/minimizer.rb index 303bd1fe..2d131f7c 100644 --- a/lib/virtual/passes/minimizer.rb +++ b/lib/virtual/passes/minimizer.rb @@ -11,7 +11,7 @@ module Virtual @gonners << f end end - init= Parfait::Space.object_space.get_class_by_name("Kernel").get_instance_method "__init__" + init= Parfait::Space.object_space.get_class_by_name(:Kernel).get_instance_method :__init__ remove init dump_remaining end diff --git a/lib/virtual/passes/send_implementation.rb b/lib/virtual/passes/send_implementation.rb index 9ab72dbc..6e5ce675 100644 --- a/lib/virtual/passes/send_implementation.rb +++ b/lib/virtual/passes/send_implementation.rb @@ -39,8 +39,11 @@ module Virtual if ref.type.is_a?(Reference) and ref.type.of_class #find method and call clazz = ref.type.of_class - method = clazz.resolve_method code.name.to_s - raise "No method found #{code.name}" unless method + begin + method = clazz.resolve_method code.name + rescue + raise "No method found #{code.name} for #{clazz.name} in #{clazz.method_names}" unless method + end new_codes << MethodCall.new( method ) else # must defer send to run-time diff --git a/test/arm/test_move.rb b/test/arm/test_move.rb index b8770d5e..32780001 100644 --- a/test/arm/test_move.rb +++ b/test/arm/test_move.rb @@ -33,7 +33,7 @@ class TestMoves < MiniTest::Test assert_code code , :mvn , [0x05,0x10,0xe0,0xe3] #e3 e0 10 05 end def test_constant_small # like test_mov - const = Virtual.new_word "harvey" + const = :harvey const.set_position( 13 ) # 13 = 5 + 8 , 8 for the arm pipeline offset, gets subtracted code = @machine.mov :r1 , 5 code.set_position(0) @@ -41,7 +41,7 @@ class TestMoves < MiniTest::Test assert_code code , :mov , [0x05,0x10,0xa0,0xe3] #e3 ef 10 05 end def test_constant_big # like test_mov_big - const = Virtual.new_word "harvey" + const = :harvey const.set_position( 0x222 ) code = @machine.mov :r0 , 0x222 code.set_position(0) diff --git a/test/virtual/virtual_helper.rb b/test/virtual/virtual_helper.rb index fcebe661..1ec58ec6 100644 --- a/test/virtual/virtual_helper.rb +++ b/test/virtual/virtual_helper.rb @@ -28,7 +28,17 @@ module VirtualHelper end end - +module Virtual + # Functions to generate parfait objects + def self.new_word( string ) + string = string.to_s if string.is_a? Symbol + word = Parfait::Word.new_object( string.length ) + string.codepoints.each_with_index do |code , index | + word.set_char(index + 1 , code) + end + word + end +end class UnusedSofEquality # simple thought: don't recurse for Blocks, just check their names def == other