///|
fn Machine::dictionary_key(
self : Machine,
text : Array[Int32],
) -> Array[Int32] raise Fault {
let count = if self.version == 3 { 6 } else { 9 }
let zs : Array[Int32] = []
let custom = if self.version == 5 { self.word(52) } else { 0 }
for code in text {
if zs.length() >= count {
break
}
if code == 32 {
zs.push(0)
continue
}
let mut found = false
for alphabet in 0..<3 {
for idx in 0..<26 {
if alphabet == 2 && idx == 0 {
continue
}
let value = if custom != 0 {
self.byte(custom + alphabet * 26 + idx)
} else if alphabet == 0 {
97 + idx
} else if alphabet == 1 {
65 + idx
} else if idx == 1 {
13
} else {
"0123456789.,!?_#'\"/\\-:()"[idx - 2].to_int()
}
if value == code {
if alphabet != 0 {
zs.push(alphabet + 3)
}
zs.push(idx + 6)
found = true
break
}
}
if found {
break
}
}
if !found {
zs.push(5)
zs.push(6)
zs.push((code >> 5) & 31)
zs.push(code & 31)
}
}
while zs.length() < count {
zs.push(5)
}
let result : Array[Int32] = []
for i in 0..<(count / 3) {
let w = (zs[i * 3] << 10) |
(zs[i * 3 + 1] << 5) |
zs[i * 3 + 2] |
(if i == count / 3 - 1 { 32768 } else { 0 })
result.push(w >> 8)
result.push(w & 255)
}
result
}
///|
fn Machine::encode_dictionary(
self : Machine,
data : Array[Int32],
destination : Int32,
) -> Unit raise Fault {
let key = self.dictionary_key(data)
for i in 0.. Int32 raise Fault {
let key = self.dictionary_key(text)
let count = self.byte(dictionary)
let stride = self.byte(dictionary + 1 + count)
let raw = signed(self.word(dictionary + 2 + count))
let entries = if raw < 0 { -raw } else { raw }
let base = dictionary + 4 + count
if stride < key.length() {
raise Invalid("dictionary entries too short")
}
if entries > (self.mem.length() - base) / stride {
raise Invalid("truncated dictionary")
}
// A linear lookup also handles unsorted user dictionaries without trusting their order.
for i in 0.. Unit raise Fault {
if parse == 0 {
return
}
let dictionary = if custom == 0 { self.word(8) } else { custom }
let separators = self.byte(dictionary)
let start = if self.version == 3 { 1 } else { 2 }
let length = if self.version == 5 {
self.byte(buffer + 1)
} else {
let mut n = 0
while self.byte(buffer + 1 + n) != 0 {
n += 1
if n >= self.byte(buffer) {
raise Invalid("unterminated v3 input")
}
}
n
}
let max = self.byte(parse)
let mut count = 0
let mut i = 0
while i < length && count < max {
let code = self.byte(buffer + start + i)
if code == 32 {
i += 1
continue
}
let token_start = i
let is_sep = fn(c) raise Fault {
let mut found = false
for j in 0.. Unit raise Fault {
if self.waiting != 1 {
raise Invalid("interpreter is not waiting for a line")
}
let data : Array[Int32] = []
let max = self.byte(self.input_buffer) -
(if self.version == 3 { 1 } else { 0 })
for c in line.to_array() {
let code = c.to_int()
if code == 10 || code == 13 {
break
}
if code < 32 || code > 126 {
raise Invalid("line input currently supports printable ASCII")
}
if data.length() < max {
data.push(if code >= 65 && code <= 90 { code + 32 } else { code })
}
}
let start = if self.version == 3 { 1 } else { 2 }
for i in 0..= 0 {
self.assign(self.input_store, 13)
}
self.waiting = 0
}
///|
/// Supply a ZSCII character when run returns "char".
pub fn Machine::send_char(self : Machine, code : Int32) -> Unit raise Fault {
if self.waiting != 2 || code < 0 || code > 255 {
raise Invalid("invalid character input")
}
self.assign(self.input_store, code)
self.waiting = 0
}