fix word implementation and tests
much better, though wasteful implementation breaks a few tests, but ploughing on first
This commit is contained in:
parent
164816c441
commit
0731a6061a
@ -21,40 +21,41 @@ module FakeMem
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Parfait::Object
|
module Parfait
|
||||||
include FakeMem
|
class Object
|
||||||
def self.new_object *args
|
include FakeMem
|
||||||
#puts "I am #{self}"
|
def self.new_object *args
|
||||||
object = self.new(*args)
|
#puts "I am #{self}"
|
||||||
object
|
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
|
end
|
||||||
def internal_object_length
|
class Parfait::Class
|
||||||
@memory.length
|
|
||||||
end
|
end
|
||||||
def internal_object_get(index)
|
class Parfait::List
|
||||||
@memory[index]
|
def length
|
||||||
|
internal_object_length
|
||||||
|
end
|
||||||
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
|
# Functions to generate parfait objects
|
||||||
String.class_eval do
|
def self.new_word( string )
|
||||||
def to_word
|
string = string.to_s if string.is_a? Symbol
|
||||||
word = Parfait::Word.new( self.length )
|
word = Parfait::Word.new( string.length )
|
||||||
codepoints.each_with_index do |code , index |
|
string.codepoints.each_with_index do |code , index |
|
||||||
word.set_char(index , char)
|
word.set_char(index , code)
|
||||||
end
|
end
|
||||||
word
|
word
|
||||||
end
|
end
|
||||||
|
@ -7,20 +7,32 @@ module Parfait
|
|||||||
#
|
#
|
||||||
# Words are constant, maybe like js strings, ruby symbols
|
# Words are constant, maybe like js strings, ruby symbols
|
||||||
# Words are short, but may have spaces
|
# Words are short, but may have spaces
|
||||||
|
|
||||||
|
# big TODO , this has NO encoding, a char takes a machine word. Go fix.
|
||||||
class Word < Object
|
class Word < Object
|
||||||
# initialize with length. For now we try to keep all non-parfait (including String) out
|
# initialize with length. For now we try to keep all non-parfait (including String) out
|
||||||
# Virtual provides methods to create Parfait objects from ruby
|
# Virtual provides methods to create Parfait objects from ruby
|
||||||
def initialize length
|
def initialize len
|
||||||
super
|
super()
|
||||||
set_length( length , 32 )
|
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
|
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)
|
def set_length(len , fill_char)
|
||||||
return if len < 0
|
return if len < 0
|
||||||
counter = self.length()
|
counter = self.length()
|
||||||
return if len >= counter
|
return if counter >= len
|
||||||
internal_object_grow( ( len + 1 ) / 2)
|
internal_object_grow( len )
|
||||||
while( counter < len)
|
while( counter < len)
|
||||||
set_char( counter , fill_char)
|
set_char( counter , fill_char)
|
||||||
counter = counter + 1
|
counter = counter + 1
|
||||||
@ -28,36 +40,25 @@ module Parfait
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_char at , char
|
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)
|
index = range_correct_index(at)
|
||||||
was = internal_object_get(index / 2 )
|
internal_object_set( index , char )
|
||||||
if index % 2
|
|
||||||
char = (char << 16) + (was & 0xFFFF)
|
|
||||||
else
|
|
||||||
char = char + (was & 0xFFFF0000)
|
|
||||||
end
|
|
||||||
internal_object_set( index / 2 , char )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_char at
|
def get_char at
|
||||||
index = range_correct_index(at)
|
index = range_correct_index(at)
|
||||||
whole = internal_object_get(index / 2 )
|
return internal_object_get(index)
|
||||||
if index % 2
|
|
||||||
char = whole >> 16
|
|
||||||
else
|
|
||||||
char = whole & 0xFFFF
|
|
||||||
end
|
|
||||||
return char
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def range_correct_index at
|
def range_correct_index at
|
||||||
index = at
|
index = at
|
||||||
index = self.length + at if at < 0
|
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
|
return index
|
||||||
end
|
end
|
||||||
|
|
||||||
def == other
|
def == other
|
||||||
|
return false if other.class != self.class
|
||||||
return false if other.length != self.length
|
return false if other.length != self.length
|
||||||
len = self.length
|
len = self.length
|
||||||
while len
|
while len
|
||||||
@ -66,7 +67,7 @@ module Parfait
|
|||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
def result= value
|
def result= value
|
||||||
raise "called"
|
raise "called"
|
||||||
class_for(MoveInstruction).new(value , self , :opcode => :mov)
|
class_for(MoveInstruction).new(value , self , :opcode => :mov)
|
||||||
|
@ -71,7 +71,7 @@ module Virtual
|
|||||||
|
|
||||||
# attr_reader :string
|
# attr_reader :string
|
||||||
def self.compile_string expression , method
|
def self.compile_string expression , method
|
||||||
value = Parfait::Word.new(expression.string)
|
value = Parfait.new_word(expression.string)
|
||||||
to = Return.new(Reference , value)
|
to = Return.new(Reference , value)
|
||||||
Machine.instance.space.add_object value
|
Machine.instance.space.add_object value
|
||||||
method.add_code Set.new( to , value )
|
method.add_code Set.new( to , value )
|
||||||
|
@ -8,7 +8,7 @@ module Virtual
|
|||||||
me = Compiler.compile( expession.receiver , method )
|
me = Compiler.compile( expession.receiver , method )
|
||||||
method.add_code NewMessage.new
|
method.add_code NewMessage.new
|
||||||
method.add_code Set.new(NewSelf.new(me.type), me)
|
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 = []
|
compiled_args = []
|
||||||
expession.args.each_with_index do |arg , i|
|
expession.args.each_with_index do |arg , i|
|
||||||
#compile in the running method, ie before passing control
|
#compile in the running method, ie before passing control
|
||||||
|
@ -26,7 +26,7 @@ module Virtual
|
|||||||
# compile the false block
|
# compile the false block
|
||||||
method.current false_block
|
method.current false_block
|
||||||
expression.if_false.each do |part|
|
expression.if_false.each do |part|
|
||||||
puts "compiling in if false #{part}"
|
#puts "compiling in if false #{part}"
|
||||||
last = Compiler.compile(part,method )
|
last = Compiler.compile(part,method )
|
||||||
raise part.inspect if last.nil?
|
raise part.inspect if last.nil?
|
||||||
end
|
end
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
require_relative "test_list"
|
require_relative "test_list"
|
||||||
|
require_relative "test_word"
|
||||||
require_relative "test_dictionary"
|
require_relative "test_dictionary"
|
||||||
|
@ -8,15 +8,26 @@ class TestList < MiniTest::Test
|
|||||||
def test_list_create
|
def test_list_create
|
||||||
assert @list.empty?
|
assert @list.empty?
|
||||||
end
|
end
|
||||||
|
def test_list_len
|
||||||
|
assert_equal 0 , @list.length
|
||||||
|
end
|
||||||
def test_empty_list_doesnt_return
|
def test_empty_list_doesnt_return
|
||||||
assert_equal nil , @list.get(3)
|
assert_equal nil , @list.get(3)
|
||||||
end
|
end
|
||||||
def test_one_set0
|
def test_one_set0
|
||||||
assert_equal 1 , @list.set(0,1)
|
assert_equal 1 , @list.set(0,1)
|
||||||
end
|
end
|
||||||
|
def test_set0_len
|
||||||
|
@list.set(0,1)
|
||||||
|
assert_equal 1 , @list.length
|
||||||
|
end
|
||||||
def test_one_set1
|
def test_one_set1
|
||||||
assert_equal :some , @list.set(1,:some)
|
assert_equal :some , @list.set(1,:some)
|
||||||
end
|
end
|
||||||
|
def test_set1_len
|
||||||
|
@list.set(1,:some)
|
||||||
|
assert_equal 2 , @list.length
|
||||||
|
end
|
||||||
def test_two_sets
|
def test_two_sets
|
||||||
assert_equal 1 , @list.set(0,1)
|
assert_equal 1 , @list.set(0,1)
|
||||||
assert_equal :some , @list.set(1,:some)
|
assert_equal :some , @list.set(1,:some)
|
||||||
|
86
test/parfait/test_word.rb
Normal file
86
test/parfait/test_word.rb
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user