///|
fn Machine::allocate(self : Machine, count : Int) -> Unit raise ForthError {
if count < -self.memory.length() || count > 65536 - self.memory.length() {
raise Invalid("data space limit")
}
if count >= 0 {
for _ in 0.. Unit raise ForthError {
if count < 0 {
raise Invalid("invalid data space range")
}
if address >= 0 &&
address <= self.memory.length() &&
count <= self.memory.length() - address {
return
}
if address >= 65536 && address <= 66560 && count <= 66560 - address {
return
}
if address >= 1048576 &&
address - 1048576 <= self.strings.length() &&
count <= self.strings.length() - (address - 1048576) {
return
}
for frame in self.sources {
if address >= frame.address &&
address - frame.address <= frame.data.length() &&
count <= frame.data.length() - (address - frame.address) {
return
}
}
raise Invalid("invalid data space range")
}
///|
fn Machine::load(
self : Machine,
address : Int,
cell : Bool,
) -> Int raise ForthError {
if address == -4 && cell {
return if self.compilation_state { -1 } else { 0 }
}
if !cell && address == -4 {
return if self.compilation_state { 255 } else { 0 }
}
if cell && address == -8 {
return self.base
}
if cell && address == -12 {
return self.source_frame().cursor
}
self.memory_range(address, if cell { 4 } else { 1 })
if cell {
if address % 4 != 0 {
raise Invalid("unaligned cell address")
}
self.read_byte(address).to_int() |
(self.read_byte(address + 1).to_int() << 8) |
(self.read_byte(address + 2).to_int() << 16) |
(self.read_byte(address + 3).to_int() << 24)
} else {
self.read_byte(address).to_int()
}
}
///|
fn Machine::save(
self : Machine,
address : Int,
value : Int,
cell : Bool,
) -> Unit raise ForthError {
if cell && address == -8 {
if value < 2 || value > 36 {
raise Invalid("BASE must be 2..36")
}
self.base = value
return
}
if cell && address == -12 {
let frame = self.source_frame()
if value < 0 || value > frame.data.length() {
raise Invalid("invalid input cursor")
}
frame.cursor = value
return
}
self.memory_range(address, if cell { 4 } else { 1 })
if cell {
if address % 4 != 0 {
raise Invalid("unaligned cell address")
}
for i in 0..<4 {
self.write_byte(address + i, (value >> (8 * i)).to_byte())
}
} else {
self.write_byte(address, value.to_byte())
}
}