rubyx/lib/parfait/word.rb
Torsten Ruger 278eccbed5 derive binary code form word
long ago hacked the binary code to use integers (thus forsaking correct
arm binaries)
Finally fix by deriving from Word which now has correct binary access
Dumped binary.name in the process, that is available from the method
2015-11-14 15:04:04 +02:00

165 lines
5.1 KiB
Ruby

module Parfait
# A word is a a short sequence of characters
# Characters are not modeled as objects but as (small) integers
# The small means two of them have to fit into a machine word, utf16 or similar
#
# Words are constant, maybe like js strings, ruby symbols
# Words are short, but may have spaces
# Words are objects, that means they carry Layout as index 0
# So all indexes are offset by one in the implementation
# Object length is measured in non-layout cells though
class Word < Object
attribute :char_length
#semi "indexed" methods for interpreter
def self.get_length_index
2 # 2 is the amount of attributes, layout and char_length. the offset after which chars start
end
def self.get_indexed i
i + get_length_index
end
# initialize with length. For now we try to keep all non-parfait (including String) out
# String will contain spaces for non-zero length
# Register provides methods to create Parfait objects from ruby
def initialize len
super()
self.char_length = 0
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 , 32 ) unless len == 0 #32 beeing ascii space
#puts "layout #{self.get_layout} #{self.object_id.to_s(16)}"
end
# return a copy of self
def copy
cop = Word.new( self.length )
index = 1
while( index <= self.length )
cop.set_char(index , self.get_char(index))
index = index + 1
end
cop
end
# return the number of characters
def length()
obj_len = self.char_length
return obj_len
end
# make every char equal the given one
def fill_with char
fill_from_with(0 , char)
end
def fill_from_with from , char
len = self.length()
return if from <= 0
while( from <= len)
set_char( from , char)
from = from + 1
end
from
end
# true if no characters
def empty?
return self.length == 0
end
# pad the string with the given character to the given length
#
def set_length(len , fill_char)
return if len <= 0
old = self.char_length
return if old >= len
self.char_length = len
check_length
fill_from_with( old + 1 , fill_char )
end
# set the character at the given index to the given character
# character must be an integer, as is the index
# the index starts at one, but may be negative to count from the end
# indexes out of range will raise an error
def set_char at , char
raise "char not fixnum #{char.class}" unless char.kind_of? Fixnum
index = range_correct_index(at)
word_index = (index - 1) / 4 + 1 + Word.get_length_index
rest = ((index - 1) % 4)
shifted = char << (rest * 8)
was = get_internal( word_index )
was = 0 unless was.is_a?(Numeric)
mask = 0xFF << (rest * 8)
mask = 0xFFFFFFFF - mask
masked = was & mask
put = masked + shifted
set_internal( word_index , put )
msg = "set index=#{index} word_index=#{word_index} rest=#{rest}= "
msg += "char=#{char.to_s(16)} shifted=#{shifted.to_s(16)} "
msg += "was=#{was.to_s(16)} masked=#{masked.to_s(16)} put=#{put.to_s(16)}"
#puts msg
char
end
# get the character at the given index (lowest 1)
# the index starts at one, but may be negative to count from the end
# indexes out of range will raise an error
#the return "character" is an integer
def get_char at
index = range_correct_index(at)
word_index = (index - 1 ) / 4 + 1 + Word.get_length_index
rest = ((index - 1) % 4)
char = get_internal(word_index)
char = 0 unless char.is_a?(Numeric)
shifted = char >> (8 * rest)
ret = shifted & 0xFF
msg = "get index=#{index} word_index=#{word_index} rest=#{rest}= "
msg += " char=#{char.to_s(16)} shifted=#{shifted.to_s(16)} ret=#{ret.to_s(16)}"
#puts msg
return ret
end
# private method to calculate negative indexes into positives
def range_correct_index at
index = at
index = self.length + at if at < 0
raise "index must be positive , not #{at}" if (index <= 0)
raise "index too large #{at} > #{self.length}" if (index > self.length )
return index
end
# compare the word to another
# currently checks for same class, though really identity of the characters
# in right order would suffice
def == other
return false if other.class != self.class
return false if other.length != self.length
len = self.length
while(len > 0)
return false if self.get_char(len) != other.get_char(len)
len = len - 1
end
return true
end
# as we answered is_value? with true, sof will create a basic node with this string
def to_sof
"'" + to_s + "'"
end
def padded_length
padded( 4 * get_layout().instance_length + self.char_length )
end
private
def check_length
raise "Length out of bounds #{self.char_length}" if self.char_length > 108
end
end
end