diff --git a/lib/parfait.rb b/lib/parfait.rb index b0c11269..9cf51a88 100644 --- a/lib/parfait.rb +++ b/lib/parfait.rb @@ -21,40 +21,41 @@ module FakeMem end end -class Parfait::Object - include FakeMem - def self.new_object *args - #puts "I am #{self}" - object = self.new(*args) - object +module Parfait + class Object + include FakeMem + def self.new_object *args + #puts "I am #{self}" + object = self.new(*args) + object + end + def internal_object_length + @memory.length + end + def internal_object_get(index) + @memory[index] + end + def internal_object_set(index , value) + @memory[index] = value + end + def internal_object_grow(index) + @memory[index] = nil + end end - def internal_object_length - @memory.length + class Parfait::Class end - def internal_object_get(index) - @memory[index] + class Parfait::List + def length + internal_object_length + end end - def internal_object_set(index , value) - @memory[index] = value - end - def internal_object_grow(index) - @memory[index] = nil - end -end -class Parfait::Class -end -class Parfait::List - def length - internal_object_length - end -end -# Functions to generate parfait objects -String.class_eval do - def to_word - word = Parfait::Word.new( self.length ) - codepoints.each_with_index do |code , index | - word.set_char(index , char) + # Functions to generate parfait objects + def self.new_word( string ) + string = string.to_s if string.is_a? Symbol + word = Parfait::Word.new( string.length ) + string.codepoints.each_with_index do |code , index | + word.set_char(index , code) end word end diff --git a/lib/parfait/word.rb b/lib/parfait/word.rb index cca9bb36..3a9a2d77 100644 --- a/lib/parfait/word.rb +++ b/lib/parfait/word.rb @@ -7,20 +7,32 @@ module Parfait # # Words are constant, maybe like js strings, ruby symbols # Words are short, but may have spaces + + # big TODO , this has NO encoding, a char takes a machine word. Go fix. class Word < Object # initialize with length. For now we try to keep all non-parfait (including String) out # Virtual provides methods to create Parfait objects from ruby - def initialize length - super - set_length( length , 32 ) + def initialize len + super() + raise "Must init with int, not #{len.class}" unless len.kind_of? Fixnum + raise "Must init with positive, not #{len}" if len < 0 + set_length( len - 1, 32 ) unless len == 0 end + def length() + obj_len = internal_object_length + return obj_len + end + + def empty? + return self.length == 0 + end def set_length(len , fill_char) return if len < 0 counter = self.length() - return if len >= counter - internal_object_grow( ( len + 1 ) / 2) + return if counter >= len + internal_object_grow( len ) while( counter < len) set_char( counter , fill_char) counter = counter + 1 @@ -28,36 +40,25 @@ module Parfait end def set_char at , char - raise "char out of range #{char}" if (char < 0) or (char > 65000) + raise "char not fixnum #{char}" unless char.kind_of? Fixnum index = range_correct_index(at) - was = internal_object_get(index / 2 ) - if index % 2 - char = (char << 16) + (was & 0xFFFF) - else - char = char + (was & 0xFFFF0000) - end - internal_object_set( index / 2 , char ) + internal_object_set( index , char ) end def get_char at index = range_correct_index(at) - whole = internal_object_get(index / 2 ) - if index % 2 - char = whole >> 16 - else - char = whole & 0xFFFF - end - return char + return internal_object_get(index) end def range_correct_index at index = at index = self.length + at if at < 0 - raise "index out of range #{at}" if index < 0 + raise "index out of bounds #{at} > #{self.length}" if (index < 0) or (index > self.length) return index end def == other + return false if other.class != self.class return false if other.length != self.length len = self.length while len @@ -66,7 +67,7 @@ module Parfait end return true end - + def result= value raise "called" class_for(MoveInstruction).new(value , self , :opcode => :mov) diff --git a/lib/virtual/compiler/basic_expressions.rb b/lib/virtual/compiler/basic_expressions.rb index 1dcf890c..934d3c1b 100644 --- a/lib/virtual/compiler/basic_expressions.rb +++ b/lib/virtual/compiler/basic_expressions.rb @@ -71,7 +71,7 @@ module Virtual # attr_reader :string def self.compile_string expression , method - value = Parfait::Word.new(expression.string) + value = Parfait.new_word(expression.string) to = Return.new(Reference , value) Machine.instance.space.add_object value method.add_code Set.new( to , value ) diff --git a/lib/virtual/compiler/callsite_expression.rb b/lib/virtual/compiler/callsite_expression.rb index 1d17003b..1650f423 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.add_code NewMessage.new method.add_code Set.new(NewSelf.new(me.type), me) - method.add_code Set.new(NewName.new(), Parfait::Word.new(expession.name)) + method.add_code Set.new(NewName.new(), Parfait.new_word(expession.name)) compiled_args = [] expession.args.each_with_index do |arg , i| #compile in the running method, ie before passing control diff --git a/lib/virtual/compiler/if_expression.rb b/lib/virtual/compiler/if_expression.rb index 13e2b798..8e24f29e 100644 --- a/lib/virtual/compiler/if_expression.rb +++ b/lib/virtual/compiler/if_expression.rb @@ -26,7 +26,7 @@ module Virtual # compile the false block method.current false_block expression.if_false.each do |part| - puts "compiling in if false #{part}" + #puts "compiling in if false #{part}" last = Compiler.compile(part,method ) raise part.inspect if last.nil? end diff --git a/test/parfait/test_all.rb b/test/parfait/test_all.rb index 3ff168af..3576a7e1 100644 --- a/test/parfait/test_all.rb +++ b/test/parfait/test_all.rb @@ -1,2 +1,3 @@ require_relative "test_list" +require_relative "test_word" require_relative "test_dictionary" diff --git a/test/parfait/test_list.rb b/test/parfait/test_list.rb index 93db6b6a..9d98d70a 100644 --- a/test/parfait/test_list.rb +++ b/test/parfait/test_list.rb @@ -8,15 +8,26 @@ class TestList < MiniTest::Test def test_list_create assert @list.empty? end + def test_list_len + assert_equal 0 , @list.length + end def test_empty_list_doesnt_return assert_equal nil , @list.get(3) end def test_one_set0 assert_equal 1 , @list.set(0,1) end + def test_set0_len + @list.set(0,1) + assert_equal 1 , @list.length + end def test_one_set1 assert_equal :some , @list.set(1,:some) end + def test_set1_len + @list.set(1,:some) + assert_equal 2 , @list.length + end def test_two_sets assert_equal 1 , @list.set(0,1) assert_equal :some , @list.set(1,:some) diff --git a/test/parfait/test_word.rb b/test/parfait/test_word.rb new file mode 100644 index 00000000..e3d072e8 --- /dev/null +++ b/test/parfait/test_word.rb @@ -0,0 +1,86 @@ +require_relative "../helper" + +class TestEmptyWord < MiniTest::Test + + def setup + @list = ::Parfait::Word.new_object(0) + end + def test_list_create + assert @list.empty? + end + def test_empty_is_zero + assert_equal 0 , @list.length + end + def test_index_check_get + assert_raises RuntimeError do + @list.get_char(1) + end + end + def test_index_check_set + assert_raises RuntimeError do + @list.set_char(1 , 32) + end + end +end +class TestWord < MiniTest::Test + + def setup + @list = ::Parfait::Word.new_object(5) + end + def test_len + assert_equal 5 , @list.length + end + def test_index_check_get + assert_raises RuntimeError do + @list.get_char(-6) + end + end + def test_index_check_set + assert_raises RuntimeError do + @list.set_char(6 , 32) + end + end + def test_index_check_get + assert_raises RuntimeError do + @list.get_char(6) + end + end + def test_index_check_set + assert_raises RuntimeError do + @list.set_char(-6 , 32) + end + end + def pest_one_char + assert 32 , @list.set_char(1 , 32) + end + def pest_empty_list_doesnt_return + assert_equal nil , @list.get(3) + end + def pest_one_set0 + assert_equal 1 , @list.set(0,1) + end + def pest_one_set1 + assert_equal :some , @list.set(1,:some) + end + def pest_two_sets + assert_equal 1 , @list.set(0,1) + assert_equal :some , @list.set(1,:some) + end + def pest_one_get1 + pest_one_set0 + assert_equal 1 , @list.get(0) + end + def pest_one_get2 + pest_one_set1 + assert_equal :some , @list.get(1) + end + def pest_many_get + shouldda = { 1 => :one , 2 => :two , 3 => :three} + shouldda.each do |k,v| + @list.set(k,v) + end + shouldda.each do |k,v| + assert_equal v , @list.get(k) + end + end +end