diff --git a/Makefile b/Makefile index 0b4b190fa..7f9b7de54 100644 --- a/Makefile +++ b/Makefile @@ -30,8 +30,8 @@ compiler-browser-check: cd compiler && ../node_modules/.bin/pkg --targets host . ./avm/target/release/alan: compiler/alan-compile - cd avm && cargo fmt cd avm && cargo build --release + cd avm && cargo fmt ./anycloud/cli/target/release/anycloud: compiler/alan-compile cd anycloud/cli && cargo fmt @@ -68,6 +68,6 @@ uninstall: version: ./.version.sh $(version) -.PHONY: prerelease +.PHONY: prerelease prerelease: ./.prerelease.sh $(version) \ No newline at end of file diff --git a/avm/src/main.rs b/avm/src/main.rs index 7d1d2669e..ae55840c5 100644 --- a/avm/src/main.rs +++ b/avm/src/main.rs @@ -29,7 +29,10 @@ async fn compile_and_run(source_file: &str) -> i32 { let mut path = env::current_dir().unwrap(); path.push(dest_file); let fp = path.into_os_string().into_string().unwrap(); - run_file(&fp, true).await; + if let Err(ee) = run_file(&fp, true).await { + eprintln!("{}", ee); + return 2; + }; } return status_code; } @@ -131,7 +134,10 @@ fn main() { agc_file ); telemetry::log("avm-run").await; - run_file(&fp, false).await; + if let Err(ee) = run_file(&fp, false).await { + eprintln!("{}", ee); + std::process::exit(2); + }; } ("compile", Some(matches)) => { let source_file = matches.value_of("INPUT").unwrap(); diff --git a/avm/src/vm/event.rs b/avm/src/vm/event.rs index 2a1579fae..836751709 100644 --- a/avm/src/vm/event.rs +++ b/avm/src/vm/event.rs @@ -1,5 +1,4 @@ use futures::future::join_all; -use futures::FutureExt; use std::sync::Arc; use tokio::task; @@ -8,10 +7,14 @@ use crate::vm::memory::HandlerMemory; use crate::vm::opcode::OpcodeFn; use crate::vm::program::Program; use crate::vm::run::EVENT_TX; +use crate::vm::InstrType; +use crate::vm::VMError; +use crate::vm::VMResult; pub const NOP_ID: i64 = i64::MIN; #[derive(PartialEq, Eq, Hash)] +#[repr(i64)] /// Special events in alan found in standard library modules, @std. /// The IDs for built-in events are negative to avoid collision with positive, custom event IDs. /// The first hexadecimal byte of the ID in an integer is between 80 and FF @@ -19,10 +22,10 @@ pub const NOP_ID: i64 = i64::MIN; pub enum BuiltInEvents { /// Alan application start /// '"start"' in ASCII or 2273 7461 7274 22(80) - START, + START = -9213673853036498142, /// '__conn ' in ASCII or 5f5f 636f 6e6e 20(80) - HTTPCONN, - NOP, + HTTPCONN = -9214243417005793441, + NOP = NOP_ID, } impl From for i64 { @@ -204,25 +207,29 @@ impl HandlerFragment { &mut self, mut hand_mem: Arc, instrs: &Vec, - ) -> Arc { + ) -> VMResult> { task::block_in_place(move || { - instrs.iter().for_each(|i| { - if let OpcodeFn::Cpu(func) = i.opcode.fun { - //eprintln!("{} {} {} {}", i.opcode._name, i.args[0], i.args[1], i.args[2]); - let event = func(i.args.as_slice(), &mut hand_mem); - if event.is_some() { - let event_tx = EVENT_TX.get().unwrap(); - let event_sent = event_tx.send(event.unwrap()); - if event_sent.is_err() { - eprintln!("Event transmission error"); - std::process::exit(2); + instrs + .iter() + .map(|i| { + if let OpcodeFn::Cpu(func) = i.opcode.fun { + //eprintln!("{} {} {} {}", i.opcode._name, i.args[0], i.args[1], i.args[2]); + let event = func(i.args.as_slice(), &mut hand_mem); + if let Some(event) = event? { + let event_tx = EVENT_TX.get().unwrap(); + let event_sent = event_tx.send(event); + if event_sent.is_err() { + eprintln!("Event transmission error"); + std::process::exit(2); + } } + Ok(()) + } else { + Err(VMError::UnexpectedInstruction(InstrType::CPU)) } - } else { - eprintln!("expected another CPU instruction, found an IO instruction"); - }; - }); - hand_mem + }) + .collect::>>()?; + Ok(hand_mem) }) } @@ -231,15 +238,14 @@ impl HandlerFragment { &mut self, hand_mem: Arc, instrs: &Vec, - ) -> Arc { + ) -> VMResult> { // These instructions are always in groups by themselves let op = &instrs[0]; if let OpcodeFn::UnpredCpu(func) = op.opcode.fun { //eprintln!("{} {:?}", op.opcode._name, op.args); return func(op.args.clone(), hand_mem).await; } else { - eprintln!("expected an UnpredCpu instruction"); - std::process::exit(1); + return Err(VMError::UnexpectedInstruction(InstrType::UnpredictableCPU)); } } @@ -248,36 +254,40 @@ impl HandlerFragment { &mut self, mut hand_mem: Arc, instrs: &Vec, - ) -> Arc { + ) -> VMResult> { if instrs.len() == 1 { let op = &instrs[0]; if let OpcodeFn::Io(func) = op.opcode.fun { //eprintln!("{} {:?}", op.opcode._name, op.args); return func(op.args.clone(), hand_mem).await; } else { - eprintln!("expected an IO instruction"); - std::process::exit(1); + return Err(VMError::UnexpectedInstruction(InstrType::IO)); } } else { let futures: Vec<_> = instrs .iter() .map(|i| { - if let OpcodeFn::Io(func) = i.opcode.fun { - //eprintln!("{} {:?}", i.opcode._name, i.args); - func(i.args.clone(), HandlerMemory::fork(hand_mem.clone())) - .then(HandlerMemory::drop_parent_async) - } else { - eprintln!("expected another IO instruction"); - std::process::exit(1); + let hand_mem = hand_mem.clone(); + async move { + if let OpcodeFn::Io(func) = i.opcode.fun { + //eprintln!("{} {:?}", i.opcode._name, i.args); + let forked = HandlerMemory::fork(hand_mem.clone())?; + let res = func(i.args.clone(), forked).await?; + Ok(HandlerMemory::drop_parent(res)?) + // Ok(func(i.args.clone(), HandlerMemory::fork(hand_mem.clone())?) + // .then(|res| HandlerMemory::drop_parent_async).await) + } else { + Err(VMError::UnexpectedInstruction(InstrType::IO)) + } } }) .collect(); let hms = join_all(futures).await; - for hm in hms.into_iter() { - hand_mem.join(hm); + for hm in hms { + hand_mem.join(hm?)?; } } - hand_mem + Ok(hand_mem) } /// Runs the specified handler in Tokio tasks. Tokio tasks are allocated to a threadpool bound by @@ -293,13 +303,13 @@ impl HandlerFragment { pub async fn run( mut self: HandlerFragment, mut hand_mem: Arc, - ) -> Arc { + ) -> VMResult> { loop { let instrs = self.get_instruction_fragment(); hand_mem = match instrs[0].opcode.fun { - OpcodeFn::Cpu(_) => self.run_cpu(hand_mem, instrs).await, - OpcodeFn::UnpredCpu(_) => self.run_unpred_cpu(hand_mem, instrs).await, - OpcodeFn::Io(_) => self.run_io(hand_mem, instrs).await, + OpcodeFn::Cpu(_) => self.run_cpu(hand_mem, instrs).await?, + OpcodeFn::UnpredCpu(_) => self.run_unpred_cpu(hand_mem, instrs).await?, + OpcodeFn::Io(_) => self.run_io(hand_mem, instrs).await?, }; if let Some(frag) = self.get_next_fragment() { self = frag; @@ -307,7 +317,7 @@ impl HandlerFragment { break; } } - hand_mem + Ok(hand_mem) } /// Spawns and runs a non-blocking tokio task for the fragment that can be awaited. @@ -315,7 +325,7 @@ impl HandlerFragment { pub fn spawn( self: HandlerFragment, hand_mem: Arc, - ) -> task::JoinHandle> { + ) -> task::JoinHandle>> { task::spawn(async move { self.run(hand_mem).await }) } } diff --git a/avm/src/vm/memory.rs b/avm/src/vm/memory.rs index 8d8c43e9c..173d7edc5 100644 --- a/avm/src/vm/memory.rs +++ b/avm/src/vm/memory.rs @@ -1,11 +1,10 @@ -use std::convert::TryInto; +use std::array::IntoIter; use std::str; use std::sync::Arc; -use protobuf::{Message, ProtobufError, ProtobufResult}; +use byteorder::{ByteOrder, NativeEndian}; -use crate::vm::program::Program; -use crate::vm::protos; +use crate::vm::{program::Program, protos, VMError, VMResult}; // -2^63 pub const CLOSURE_ARG_MEM_START: i64 = -9223372036854775808; @@ -69,11 +68,12 @@ impl FractalMemory { } /// Reads fixed data from a given address. - pub fn read_fixed(self: &FractalMemory, idx: usize) -> i64 { + pub fn read_fixed(self: &FractalMemory, idx: usize) -> VMResult { if self.block[idx].0 != usize::MAX { - panic!("Trying to read raw data from memory when it is a pointer") + Err(VMError::IllegalAccess) + } else { + Ok(self.block[idx].1) } - return self.block[idx].1; } } @@ -114,7 +114,10 @@ pub struct HandlerMemory { impl HandlerMemory { /// Constructs a new HandlerMemory. If given another HandlerMemory it simply adjusts it to the /// expected memory needs, otherwise constructs a new one with said memory requirements. - pub fn new(payload_mem: Option>, mem_req: i64) -> Arc { + pub fn new( + payload_mem: Option>, + mem_req: i64, + ) -> VMResult> { let mut hm = match payload_mem { Some(payload) => payload, None => Arc::new(HandlerMemory { @@ -124,10 +127,9 @@ impl HandlerMemory { parent: None, }), }; - let handlermemory = - Arc::get_mut(&mut hm).expect("Couldn't reserve in HandlerMemory: dangling pointer"); + let handlermemory = Arc::get_mut(&mut hm).ok_or_else(|| VMError::HandMemDanglingPtr)?; handlermemory.mems[1].reserve(mem_req as usize); - return hm; + return Ok(hm); } /// Grabs the relevant data for the event and constructs a new HandlerMemory with that value in @@ -136,15 +138,19 @@ impl HandlerMemory { event_id: i64, curr_addr: i64, curr_hand_mem: &Arc, - ) -> Option> { - let pls = Program::global().event_pls.get(&event_id).unwrap().clone(); + ) -> VMResult>> { + let pls = Program::global() + .event_pls + .get(&event_id) + .ok_or(VMError::EventNotDefined(event_id))? + .clone(); return if pls == 0 { // no payload, void event - None + Ok(None) } else { - let mut hm = HandlerMemory::new(None, 1); - HandlerMemory::transfer(curr_hand_mem, curr_addr, &mut hm, 0); - Some(hm) + let mut hm = HandlerMemory::new(None, 1)?; + HandlerMemory::transfer(curr_hand_mem, curr_addr, &mut hm, 0)?; + Ok(Some(hm)) }; } @@ -153,14 +159,10 @@ impl HandlerMemory { /// that cannot be performed on an object within an Arc. As a result, /// all the forked children drop their reference to the parent, we take /// the parent out of the Arc after parallel work is done and then join on its children. - pub fn drop_parent(mut self: Arc) -> Arc { - let hm = Arc::get_mut(&mut self).expect("unable to drop parent HM: dangling pointer"); + pub fn drop_parent(mut self: Arc) -> VMResult> { + let hm = Arc::get_mut(&mut self).ok_or(VMError::HandMemDanglingPtr)?; hm.parent.take(); - self - } - - pub(crate) async fn drop_parent_async(self: Arc) -> Arc { - self.drop_parent() + Ok(self) } /// Returns true if the idxs are valid in self @@ -208,89 +210,79 @@ impl HandlerMemory { fn addr_to_idxs( self: &Arc, addr: i64, - ) -> ((usize, usize), Option>) { + ) -> VMResult<((usize, usize), Option>)> { return match self.addr_to_idxs_opt(addr) { - Some(res) => (res, self.hm_for_idxs(res.0, res.1)), + Some(res) => Ok((res, self.hm_for_idxs(res.0, res.1))), None => { let (idxs, hm_opt) = self .parent .as_ref() // fail if no parent - .expect( - format!( - "Memory address {} referenced in parent, but no parent pointer defined\nhm:{:?}", - addr, self - ) - .as_str(), - ) - .addr_to_idxs(addr); + .ok_or(VMError::OrphanMemory)? + .addr_to_idxs(addr)?; let hm = match hm_opt { Some(hm) => Some(hm), None => self.parent.clone(), }; - (idxs, hm) + Ok((idxs, hm)) } }; } /// Reads fixed data from a given address. - pub fn read_fixed(self: &Arc, addr: i64) -> i64 { - let ((a, b), hm_opt) = self.addr_to_idxs(addr); + pub fn read_fixed(self: &Arc, addr: i64) -> VMResult { + let ((a, b), hm_opt) = self.addr_to_idxs(addr)?; return if a == std::usize::MAX { - b as i64 + Ok(b as i64) } else { let hm = hm_opt.as_ref().unwrap_or(self).as_ref(); - hm.mems[a][b].1 + Ok(hm.mems[a][b].1) }; } /// Reads an array of data from the given address. - pub fn read_fractal(self: &Arc, addr: i64) -> FractalMemory { - let ((a, b), hm_opt) = self.addr_to_idxs(addr); + pub fn read_fractal(self: &Arc, addr: i64) -> VMResult { + let ((a, b), hm_opt) = self.addr_to_idxs(addr)?; // eprintln!("addr: {}, self?: {}, (a,b): ({},{})", addr, hm_opt.is_none(), a, b); let hm = hm_opt.as_ref().unwrap_or(self); // Special behavior to read strings out of global memory let start = if addr_type(addr) == GMEM_ADDR { b } else { 0 }; - return FractalMemory { + return Ok(FractalMemory { hm_addr: Some(addr), block: hm.mems[a][start..].to_vec(), hm_id: Arc::as_ptr(hm) as usize, - }; + }); } /// Provides a mutable array of data from the given address. pub fn read_mut_fractal<'mem>( self: &'mem mut Arc, addr: i64, - ) -> &'mem mut Vec<(usize, i64)> { - let ((a, _), hm_opt) = self.addr_to_idxs(addr); + ) -> VMResult<&'mem mut Vec<(usize, i64)>> { + let ((a, _), hm_opt) = self.addr_to_idxs(addr)?; if let Some(hm) = hm_opt { // copy necessary data from ancestor - Arc::get_mut(self).expect("how").mems[a] = hm.mems[a].clone(); + Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?.mems[a] = hm.mems[a].clone(); } - &mut Arc::get_mut(self) - .expect("couldn't grab mutable memory: dangling pointer") - .mems[a] + Ok(&mut Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?.mems[a]) } /// You better know what you're doing if you use this pub fn read_mut_fractal_by_idx<'mem>( self: &'mem mut Arc, a: usize, - ) -> &'mem mut Vec<(usize, i64)> { + ) -> VMResult<&'mem mut Vec<(usize, i64)>> { if let Some(hm) = self.hm_for_idxs(a, std::usize::MAX) { - Arc::get_mut(self).expect("how").mems[a] = hm.mems[a].clone(); + Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?.mems[a] = hm.mems[a].clone(); } - &mut Arc::get_mut(self) - .expect("couldn't grab mutable memory. dangling pointer again") - .mems[a] + Ok(&mut Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?.mems[a]) } /// For a given address, determines if the data is a single value or an array of values, and /// returns that value either as a vector or the singular value wrapped in a vector, and a /// boolean indicating if it was a fractal value or not. - pub fn read_either(self: &Arc, addr: i64) -> (FractalMemory, bool) { - let ((a, b), hm_opt) = self.addr_to_idxs(addr); + pub fn read_either(self: &Arc, addr: i64) -> VMResult<(FractalMemory, bool)> { + let ((a, b), hm_opt) = self.addr_to_idxs(addr)?; let hm = match hm_opt.as_ref() { Some(hm) => hm, None => self, @@ -300,20 +292,20 @@ impl HandlerMemory { } else { (hm.mems[a].clone(), true) }; - return ( + return Ok(( FractalMemory { hm_addr: Some(addr), block, hm_id: Arc::as_ptr(hm) as usize, }, is_fractal, - ); + )); } /// Simply sets a given address to an explicit set of `mems` indexes. Simplifies pointer creation /// to deeply-nested data. - fn set_addr(self: &mut Arc, addr: i64, a: usize, b: usize) { - let hm = Arc::get_mut(self).expect("unable to set address in HM: dangling pointer"); + fn set_addr(self: &mut Arc, addr: i64, a: usize, b: usize) -> VMResult<()> { + let hm = Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?; if addr_type(addr) == NORMAL_ADDR { let addru = addr as usize; if hm.addr.0.len() <= addru { @@ -327,6 +319,7 @@ impl HandlerMemory { } hm.addr.1[addru] = Some((a, b)); } + Ok(()) } /// For the memory block(s) starting at idx in Fractal, determines if the data is a single value or an array of @@ -373,133 +366,150 @@ impl HandlerMemory { fractal: &mut FractalMemory, idx: usize, val: i64, - ) { + ) -> VMResult<()> { fractal.block[idx].1 = val; - if fractal.belongs(self) && fractal.hm_addr.is_some() { - self.write_fractal(fractal.hm_addr.unwrap(), fractal); - } else { - panic!("Attempting to write fixed data to a fractal owned by a different HandlerMemory"); + match (fractal.belongs(self), fractal.hm_addr) { + (true, Some(addr)) => self.write_fractal(addr, fractal), + _ => Err(VMError::MemoryNotOwned), } } /// Stores a fixed value in a given address. Determines where to place it based on the kind of /// address in question. - pub fn write_fixed(self: &mut Arc, addr: i64, val: i64) { + pub fn write_fixed(self: &mut Arc, addr: i64, val: i64) -> VMResult<()> { let a = self.mem_addr; - let hm = Arc::get_mut(self).expect("couldn't write to HandlerMemory: dangling pointer"); + let hm = Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?; let b = hm.mems[a].len(); hm.mems[a].push((std::usize::MAX, val)); - self.set_addr(addr, a, b); + self.set_addr(addr, a, b) } /// Stores a nested fractal of data in a given address. - pub fn write_fractal(self: &mut Arc, addr: i64, fractal: &FractalMemory) { + pub fn write_fractal( + self: &mut Arc, + addr: i64, + fractal: &FractalMemory, + ) -> VMResult<()> { let a = self.mems.len(); if !fractal.belongs(self) { if fractal.hm_addr.is_none() { - panic!( - "Writing a forked/read-only FractalMemory that is also deeply-nested is not possible" - ); + return Err(VMError::MemoryNotOwned); } // copy fractal from ancestor - let addr = fractal.hm_addr.as_ref().unwrap().clone(); - let ((a, _), hm_opt) = self.addr_to_idxs(addr); - let hm = hm_opt.expect("couldn't write fractal to HandlerMemory: address doesn't exist"); - Arc::get_mut(self).expect("how").mems[a] = hm.mems[a].clone(); + let addr = fractal + .hm_addr + .as_ref() + .ok_or(VMError::OrphanMemory)? + .clone(); + let ((a, _), hm_opt) = self.addr_to_idxs(addr)?; + let hm = hm_opt.ok_or(VMError::IllegalAccess)?; + Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?.mems[a] = hm.mems[a].clone(); drop(hm); todo!("Writing to a fractal that a child scope has access to mutably but never acquired mutably. Please report this error!") } - let mut_self = Arc::get_mut(self).expect("couldn't write fractal to HM: dangling pointer"); + let mut_self = Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?; mut_self.mems.push(fractal.block.clone()); - self.set_addr(addr, a, std::usize::MAX); + self.set_addr(addr, a, std::usize::MAX) } /// Stores a nested empty fractal of data in a given address. - pub fn init_fractal(self: &mut Arc, addr: i64) { + pub fn init_fractal(self: &mut Arc, addr: i64) -> VMResult<()> { let a = self.mems.len(); Arc::get_mut(self) - .expect("couldn't initialize fractal: dangling pointer") + .ok_or(VMError::HandMemDanglingPtr)? .mems .push(Vec::new()); - self.set_addr(addr, a, std::usize::MAX); + self.set_addr(addr, a, std::usize::MAX) } /// Pushes a fixed value into a fractal at a given address. - pub fn push_fixed(self: &mut Arc, addr: i64, val: i64) { - let mem = self.read_mut_fractal(addr); + pub fn push_fixed(self: &mut Arc, addr: i64, val: i64) -> VMResult<()> { + let mem = self.read_mut_fractal(addr)?; mem.push((std::usize::MAX, val)); + Ok(()) } /// Pushes a nested fractal value into a fractal at a given address. - pub fn push_fractal(self: &mut Arc, addr: i64, val: FractalMemory) { + pub fn push_fractal( + self: &mut Arc, + addr: i64, + val: FractalMemory, + ) -> VMResult<()> { let a = self.mems.len(); - let mem = self.read_mut_fractal(addr); + let mem = self.read_mut_fractal(addr)?; mem.push((a, std::usize::MAX as i64)); Arc::get_mut(self) - .expect("couldn't push fractal: dangling pointer") + .ok_or(VMError::HandMemDanglingPtr)? .mems .push(val.block); + Ok(()) } /// Pops a value off of the fractal. May be fixed data or a virtual pointer. - pub fn pop(self: &mut Arc, addr: i64) -> Result { - let mem = self.read_mut_fractal(addr); + pub fn pop(self: &mut Arc, addr: i64) -> VMResult { + let mem = self.read_mut_fractal(addr)?; if mem.len() > 0 { - return Ok(FractalMemory::new(vec![mem.pop().unwrap()])); + return Ok(FractalMemory::new(vec![mem + .pop() + // if pop returned a None, that means something very bad has happened. + .ok_or(VMError::IllegalAccess)?])); } else { - return Err("cannot pop empty array".to_string()); + return Err(VMError::Other(format!("cannot pop empty array"))); } } /// Deletes a value off of the fractal at the given idx. May be fixed data or a virtual pointer. - pub fn delete( - self: &mut Arc, - addr: i64, - idx: usize, - ) -> Result { - let mem = self.read_mut_fractal(addr); + pub fn delete(self: &mut Arc, addr: i64, idx: usize) -> VMResult { + let mem = self.read_mut_fractal(addr)?; if mem.len() > 0 && mem.len() > idx { return Ok(FractalMemory::new(vec![mem.remove(idx)])); } else { - return Err(format!( + return Err(VMError::Other(format!( "cannot remove idx {} from array with length {}", idx, mem.len() - )); + ))); } } /* REGISTER MANIPULATION METHODS */ /// Creates a pointer from `orig_addr` to `addr` - pub fn register(self: &mut Arc, addr: i64, orig_addr: i64, is_variable: bool) { - let ((a, b), _) = self.addr_to_idxs(orig_addr); + pub fn register( + self: &mut Arc, + addr: i64, + orig_addr: i64, + is_variable: bool, + ) -> VMResult<()> { + let ((a, b), _) = self.addr_to_idxs(orig_addr)?; if addr_type(orig_addr) == GMEM_ADDR && is_variable { // Special behavior to read strings out of global memory - let string = HandlerMemory::fractal_to_string(FractalMemory::new(self.mems[a][b..].to_vec())); - self.write_fractal(addr, &HandlerMemory::str_to_fractal(&string)); + let string = + HandlerMemory::fractal_to_string(FractalMemory::new(self.mems[a][b..].to_vec()))?; + self.write_fractal(addr, &HandlerMemory::str_to_fractal(&string)) } else { - self.set_addr(addr, a, b); + self.set_addr(addr, a, b) } } /// Pushes a pointer from `orig_addr` address into the fractal at `addr`. - pub fn push_register(self: &mut Arc, addr: i64, orig_addr: i64) { - let ((a, b), _) = self.addr_to_idxs(orig_addr); + pub fn push_register(self: &mut Arc, addr: i64, orig_addr: i64) -> VMResult<()> { + let ((a, b), _) = self.addr_to_idxs(orig_addr)?; // Special path for strings in global memory which is the same for parent and self if a == 0 { let strmem = self.mems[0][b..].to_vec().clone(); let new_a = self.mems.len(); Arc::get_mut(self) - .expect("couldn't push register: dangling pointer") + .ok_or(VMError::HandMemDanglingPtr)? .mems .push(strmem); - let mem = self.read_mut_fractal(addr); + let mem = self.read_mut_fractal(addr)?; mem.push((new_a, std::usize::MAX as i64)); } else { - let mem = self.read_mut_fractal(addr); + let mem = self.read_mut_fractal(addr)?; mem.push((a, b as i64)); } + Ok(()) } /// Creates a pointer from `orig_addr` to index/offset `offset_addr` of fractal in `fractal_addr` @@ -508,10 +518,11 @@ impl HandlerMemory { orig_addr: i64, fractal_addr: i64, offset_addr: i64, - ) { - let ((a, b), _) = self.addr_to_idxs(orig_addr); - let mem = self.read_mut_fractal(fractal_addr); + ) -> VMResult<()> { + let ((a, b), _) = self.addr_to_idxs(orig_addr)?; + let mem = self.read_mut_fractal(fractal_addr)?; mem[offset_addr as usize] = (a, b as i64); + Ok(()) } /// Creates a pointer from index/offset `offset_addr` of fractal in `fractal_addr` to `out_addr` @@ -521,14 +532,14 @@ impl HandlerMemory { fractal_addr: i64, offset_addr: usize, out_addr: i64, - ) { - let ((arr_a, _), _) = self.addr_to_idxs(fractal_addr); - let fractal = self.read_fractal(fractal_addr); + ) -> VMResult<()> { + let ((arr_a, _), _) = self.addr_to_idxs(fractal_addr)?; + let fractal = self.read_fractal(fractal_addr)?; let (a, b) = fractal.block[offset_addr]; if a < std::usize::MAX { - self.set_addr(out_addr, a, b as usize); + self.set_addr(out_addr, a, b as usize) } else { - self.set_addr(out_addr, arr_a, offset_addr); + self.set_addr(out_addr, arr_a, offset_addr) } } @@ -539,9 +550,9 @@ impl HandlerMemory { out_addr: i64, fractal: &FractalMemory, idx: usize, - ) { + ) -> VMResult<()> { let (a, b) = fractal.block[idx]; - self.set_addr(out_addr, a, b as usize); + self.set_addr(out_addr, a, b as usize) } /// Pushes a pointer from index/offset `offset_addr` of FractalMemory to fractal at `out_addr` @@ -550,9 +561,10 @@ impl HandlerMemory { out_addr: i64, fractal: &FractalMemory, offset_addr: usize, - ) { - let mem = self.read_mut_fractal(out_addr); + ) -> VMResult<()> { + let mem = self.read_mut_fractal(out_addr)?; mem.push(fractal.block[offset_addr]); + Ok(()) } /* DATA TRANSFER, FORKING AND DUPLICATION METHODS */ @@ -564,8 +576,8 @@ impl HandlerMemory { orig_addr: i64, dest: &mut Arc, dest_addr: i64, - ) { - let ((a, b), hm_opt) = origin.addr_to_idxs(orig_addr); + ) -> VMResult<()> { + let ((a, b), hm_opt) = origin.addr_to_idxs(orig_addr)?; let orig = match hm_opt.as_ref() { Some(orig) => orig, None => origin, @@ -579,7 +591,7 @@ impl HandlerMemory { b: usize, dest: &mut Arc, dest_addr: i64, - ) { + ) -> VMResult<()> { if a == 0 { // Special behavior for global memory transfers since it may be a single value or a string let mem_slice = &orig.mems[a][b..]; @@ -590,8 +602,7 @@ impl HandlerMemory { let len = mem_slice[0].1 as usize; if len == 0 { // Assume zero is not a string - dest.write_fixed(dest_addr, mem_slice[0].1); - return; + return dest.write_fixed(dest_addr, mem_slice[0].1); } let mut s_bytes: Vec = Vec::new(); for i in 1..mem_slice.len() { @@ -600,27 +611,23 @@ impl HandlerMemory { } if len > s_bytes.len() { // Absolutely not correct - dest.write_fixed(dest_addr, mem_slice[0].1); - return; + return dest.write_fixed(dest_addr, mem_slice[0].1); } - let try_str = str::from_utf8(&s_bytes[0..len]); - if try_str.is_err() { - // Also not a string - dest.write_fixed(dest_addr, mem_slice[0].1); - } else { + match str::from_utf8(&s_bytes[0..len]) { // Well, waddaya know! - dest.write_fractal(dest_addr, &HandlerMemory::str_to_fractal(try_str.unwrap())); - return; - } + Ok(string) => return dest.write_fractal(dest_addr, &HandlerMemory::str_to_fractal(string)), + // Also not a string + Err(_) => dest.write_fixed(dest_addr, mem_slice[0].1)?, + }; } - if a == std::usize::MAX { + return if a == std::usize::MAX { // It's direct fixed data, just copy it over - dest.write_fixed(dest_addr, b as i64); + dest.write_fixed(dest_addr, b as i64) } else if a < std::usize::MAX && (b as usize) < std::usize::MAX { // All pointers are made shallow, so we know this is a pointer to a fixed value and just // grab it and de-reference it. let (_, b_nest) = orig.mems[a][b as usize]; - dest.write_fixed(dest_addr, b_nest); + dest.write_fixed(dest_addr, b_nest) } else if a < std::usize::MAX && b as usize == std::usize::MAX { // It's a nested array of data. This may itself contain references to other nested arrays of // data and is relatively complex to transfer over. First create some lookup vectors and @@ -660,44 +667,32 @@ impl HandlerMemory { } } } - if cfg!(debug_assertions) { - let strong_count = Arc::strong_count(dest); - Arc::get_mut(dest) - .expect( - format!( - "couldn't add array to destination: dangling pointer (strong count: {})", - strong_count - ) - .as_str(), - ) - .mems - .append(&mut orig_arr_copies); - } else { - Arc::get_mut(dest) - .expect(format!("couldn't add array to destination: dangling pointer").as_str()) - .mems - .append(&mut orig_arr_copies); - } + Arc::get_mut(dest) + .ok_or(VMError::HandMemDanglingPtr)? + .mems + .append(&mut orig_arr_copies); // Finally, set the destination address to point at the original, main nested array - dest.set_addr(dest_addr, dest_offset, std::usize::MAX); - } + dest.set_addr(dest_addr, dest_offset, std::usize::MAX) + } else { + Ok(()) + }; } /// Creates a duplicate of data at one address in the HandlerMemory in a new address. Makes the /// `clone` function in Alan possible. - pub fn dupe(self: &mut Arc, orig_addr: i64, dest_addr: i64) { + pub fn dupe(self: &mut Arc, orig_addr: i64, dest_addr: i64) -> VMResult<()> { // This *should be possible with something like this: // HandlerMemory::transfer(self, orig_addr, self, dest_addr); // But Rust's borrow checker doesn't like it, so we basically have to replicate the code here // despite the fact that it should work just fine... - let ((a, b), _) = self.addr_to_idxs(orig_addr); - if a == std::usize::MAX { - self.write_fixed(dest_addr, b as i64); + let ((a, b), _) = self.addr_to_idxs(orig_addr)?; + return if a == std::usize::MAX { + self.write_fixed(dest_addr, b as i64) } else if a < std::usize::MAX && (b as usize) < std::usize::MAX { // All pointers are made shallow, so we know this is a pointer to a fixed value and just // grab it and de-reference it. let (_, b_nest) = self.mems[a][b]; - self.write_fixed(dest_addr, b_nest); + self.write_fixed(dest_addr, b_nest) } else if a < std::usize::MAX && b as usize == std::usize::MAX { // It's a nested array of data. This may itself contain references to other nested arrays of // data and is relatively complex to transfer over. First create some lookup vectors and @@ -706,7 +701,7 @@ impl HandlerMemory { let mut check_idx = 0; let mut orig_arr_addrs: Vec = vec![a]; let mut orig_arr_copies: Vec> = - vec![self.read_fractal(orig_addr).block.clone()]; + vec![self.read_fractal(orig_addr)?.block.clone()]; while check_idx < orig_arr_addrs.len() { let arr = &orig_arr_copies[check_idx]; let l = arr.len(); @@ -739,23 +734,25 @@ impl HandlerMemory { } } Arc::get_mut(self) - .expect("couldn't add memory to self: dangling pointer") + .ok_or(VMError::HandMemDanglingPtr)? .mems .append(&mut orig_arr_copies); // Finally, set the destination address to point at the original, main nested array - self.set_addr(dest_addr, dest_offset, std::usize::MAX); - } + self.set_addr(dest_addr, dest_offset, std::usize::MAX) + } else { + Ok(()) + }; } /// Returns a new HandlerMemory with a read-only reference to HandlerMemory as parent - pub fn fork(parent: Arc) -> Arc { + pub fn fork(parent: Arc) -> VMResult> { let s = parent.mems.len(); - let mut hm = HandlerMemory::new(None, 1); - let handmem = Arc::get_mut(&mut hm).expect("somehow a dangling pointer for a brand new HM?"); + let mut hm = HandlerMemory::new(None, 1)?; + let handmem = Arc::get_mut(&mut hm).ok_or(VMError::HandMemDanglingPtr)?; handmem.parent = Some(parent); handmem.mems.resize(s + 1, Vec::new()); handmem.mem_addr = s; - return hm; + return Ok(hm); } /// Joins two HandlerMemory structs back together. Assumes that the passed in handler memory was @@ -766,7 +763,7 @@ impl HandlerMemory { /// /// Since the HandlerMemory has been transfered back into the original, this method assumes that /// the atomic reference is the *only one*, and consumes it so that it can't be used again. - pub fn join(self: &mut Arc, mut hm: Arc) { + pub fn join(self: &mut Arc, mut hm: Arc) -> VMResult<()> { let s = hm.mem_addr; // The initial block that will be transferred (plus all following blocks) let s2 = self.mems.len(); // The new address of the initial block let offset = s2 - s; // Assuming it was made by `fork` this should be positive or zero @@ -777,13 +774,12 @@ impl HandlerMemory { } else { 0 }; - self.set_addr(CLOSURE_ARG_MEM_START, a + off, b); + self.set_addr(CLOSURE_ARG_MEM_START, a + off, b)?; }; // println!("a: {}, b: {}, s: {}, in_fork: {}, in_parent: {}", a, b, s, hm.is_idx_defined(a, b), self.is_idx_defined(a, b)); - let hm = - Arc::get_mut(&mut hm).expect("unable to join child memory into parent: dangling pointer"); - let parent = Arc::get_mut(self).expect("unable to accept child hm: dangling pointer"); + let hm = Arc::get_mut(&mut hm).ok_or(VMError::HandMemDanglingPtr)?; + let parent = Arc::get_mut(self).ok_or(VMError::HandMemDanglingPtr)?; let updated_prev_mems = hm.mems.drain(..s); for (i, updated_prev_mem) in updated_prev_mems.enumerate() { if updated_prev_mem.len() > 0 && i > 0 { @@ -834,13 +830,13 @@ impl HandlerMemory { // However, as we start increasing efficiency in the AVM, we may eventually come to a // point where we actually *do* have to merge the parent/children memories. Until then, // the workarounds should be fine. - eprintln!("unable to merge memories"); - std::process::exit(1); + return Err(VMError::Other("Unable to merge memories".to_string())); } None => parent.addr.0[i] = Some((a + offset, b)), } } } + Ok(()) } /// Takes a UTF-8 string and converts it to fractal memory that can be stored inside of a @@ -861,10 +857,7 @@ impl HandlerMemory { loop { if i < s_bytes.len() { let s_slice = &s_bytes[i..i + 8]; - s_mem.push(( - std::usize::MAX, - i64::from_ne_bytes(s_slice.try_into().unwrap()), - )); + s_mem.push((std::usize::MAX, NativeEndian::read_i64(s_slice))); i = i + 8; } else { break; @@ -876,15 +869,17 @@ impl HandlerMemory { /// Takes a fractal memory and treats it like a UTF-8 encoded Pascal string, and the converts it /// to something Rust can work with. This function *may* crash if the underlying data is not a /// UTF-8 encoded Pascal string. - pub fn fractal_to_string(f: FractalMemory) -> String { + pub fn fractal_to_string(f: FractalMemory) -> VMResult { let s_len = f.block[0].1 as usize; - let mut s_bytes: Vec = Vec::new(); - for i in 1..f.block.len() { - let mut b = f.block[i].1.to_ne_bytes().to_vec(); - s_bytes.append(&mut b); - } - let s = str::from_utf8(&s_bytes[0..s_len]).unwrap(); - s.to_string() + let s_bytes = f + .block + .iter() + .skip(1) + // TODO: `IntoIter::new` will be deprecated once `rust-lang/rust#65819` is merged + .flat_map(|(_, chars)| IntoIter::new(chars.to_ne_bytes())) + .collect::>(); + let s = str::from_utf8(&s_bytes[0..s_len]).map_err(|_| VMError::InvalidString)?; + Ok(s.to_string()) } /// Returns a new Protobuf HandlerMemory from an existing HandlerMemory @@ -900,17 +895,17 @@ impl HandlerMemory { } /// Returns a HandlerMemory from a new Protobuf HandlerMemory - pub fn from_pb(proto_hm: &protos::HandlerMemory::HandlerMemory) -> Arc { - let mut hm = HandlerMemory::new(None, 1); - let mut hm_mut = Arc::get_mut(&mut hm).expect("unable to get memory handler"); + pub fn from_pb(proto_hm: &protos::HandlerMemory::HandlerMemory) -> VMResult> { + let mut hm = HandlerMemory::new(None, 1)?; + let mut hm_mut = Arc::get_mut(&mut hm).ok_or(VMError::HandMemDanglingPtr)?; set_mems_from_pb(&proto_hm, hm_mut); set_addr_from_pb(&proto_hm, hm_mut); if proto_hm.has_parent() { let parent = proto_hm.get_parent(); - hm_mut.parent = Some(HandlerMemory::from_pb(&parent)); + hm_mut.parent = Some(HandlerMemory::from_pb(&parent)?); } hm_mut.mem_addr = proto_hm.get_mem_addr() as usize; - hm + Ok(hm) } } diff --git a/avm/src/vm/mod.rs b/avm/src/vm/mod.rs index e2c460f24..9f8f0902c 100644 --- a/avm/src/vm/mod.rs +++ b/avm/src/vm/mod.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + pub mod event; #[macro_use] pub mod http; @@ -8,3 +10,73 @@ pub mod program; pub mod protos; pub mod run; pub mod telemetry; + +pub type VMResult = Result; + +#[derive(Debug)] +pub enum VMError { + AlreadyRunning, + EventNotDefined(i64), + FileNotFound(String), // path + HandMemDanglingPtr, + InvalidFile(String), // reason + IOError(std::io::Error), + IllegalAccess, + InvalidNOP, + InvalidString, + MemoryNotOwned, + OrphanMemory, + ShutDown, + Other(String), + UnexpectedInstruction(InstrType), +} + +impl Display for VMError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + VMError::AlreadyRunning => write!(f, "A VM instance was already detected to be running"), + VMError::EventNotDefined(event_id) => { + write!(f, "Event with event id {} is not defined", event_id) + } + VMError::FileNotFound(path) => write!(f, "File not found: {}", path), + VMError::HandMemDanglingPtr => write!(f, "There is a dangling pointer to a HandlerMemory"), + VMError::InvalidFile(reason) => write!(f, "File is invalid: {}", reason), + VMError::IOError(err) => err.fmt(f), + VMError::IllegalAccess => write!(f, "Illegal access"), + VMError::InvalidNOP => write!(f, "A NOP operation was used in an illegal context"), + VMError::InvalidString => write!(f, "Invalid string"), + VMError::MemoryNotOwned => write!( + f, + "Attempting to write to memory not owned by the current handler" + ), + VMError::OrphanMemory => write!( + f, + "Memory referenced in parent, but no parent pointer defined" + ), + VMError::ShutDown => write!(f, "The AVM instance appears to be shut down"), + VMError::Other(reason) => reason.fmt(f), + VMError::UnexpectedInstruction(instr_ty) => { + write!(f, "Expected another {} instruction", instr_ty) + } + } + } +} + +impl std::error::Error for VMError {} + +#[derive(Debug)] +pub enum InstrType { + CPU, + IO, + UnpredictableCPU, +} + +impl Display for InstrType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + InstrType::CPU => write!(f, "CPU"), + InstrType::IO => write!(f, "IO"), + InstrType::UnpredictableCPU => write!(f, "Unpredictable CPU"), + } + } +} diff --git a/avm/src/vm/opcode.rs b/avm/src/vm/opcode.rs index 2a294dee2..b19eb2890 100644 --- a/avm/src/vm/opcode.rs +++ b/avm/src/vm/opcode.rs @@ -1,4 +1,4 @@ -use futures::future::{join_all, FutureExt}; +use futures::future::join_all; use std::collections::HashMap; use std::convert::Infallible; use std::fmt::Debug; @@ -27,6 +27,7 @@ use crate::vm::http::HTTP_CLIENT; use crate::vm::memory::{FractalMemory, HandlerMemory, CLOSURE_ARG_MEM_START}; use crate::vm::program::Program; use crate::vm::run::EVENT_TX; +use crate::vm::{VMError, VMResult}; static DS: Lazy>>> = Lazy::new(|| Arc::new(DashMap::>::new())); @@ -38,11 +39,11 @@ static DS: Lazy>>> = /// For more information see: /// https://stackoverflow.com/questions/58354633/cannot-use-impl-future-to-store-async-function-in-a-vector /// https://stackoverflow.com/questions/51485410/unable-to-tokiorun-a-boxed-future-because-the-trait-bound-send-is-not-satisfie -pub type HMFuture = Pin> + Send>>; +pub type HMFuture = Pin>> + Send>>; /// A function to be run for an opcode. pub(crate) enum OpcodeFn { - Cpu(fn(&[i64], &mut Arc) -> Option), + Cpu(fn(&[i64], &mut Arc) -> VMResult>), UnpredCpu(fn(Vec, Arc) -> HMFuture), Io(fn(Vec, Arc) -> HMFuture), } @@ -99,7 +100,7 @@ pub static OPCODES: Lazy> = Lazy::new(|| { macro_rules! cpu { ($name:ident => fn ($args:ident , $hand_mem:ident) $body:block) => { #[allow(non_snake_case)] - fn $name($args: &[i64], $hand_mem: &mut Arc) -> Option { + fn $name($args: &[i64], $hand_mem: &mut Arc) -> VMResult> { $body } let id = opcode_id(stringify!($name)); @@ -222,1947 +223,1949 @@ pub static OPCODES: Lazy> = Lazy::new(|| { // Type conversion opcodes cpu!(i8f64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]) as f64; - hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes())); - None + let out = hand_mem.read_fixed(args[0])? as f64; + hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes()))?; + Ok(None) }); cpu!(i16f64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]) as f64; - hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes())); - None + let out = hand_mem.read_fixed(args[0])? as f64; + hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes()))?; + Ok(None) }); cpu!(i32f64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]) as f64; - hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes())); - None + let out = hand_mem.read_fixed(args[0])? as f64; + hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes()))?; + Ok(None) }); cpu!(i64f64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]) as f64; - hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes())); - None + let out = hand_mem.read_fixed(args[0])? as f64; + hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes()))?; + Ok(None) }); cpu!(f32f64 => fn(args, hand_mem) { - let out = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); - hand_mem.write_fixed(args[2], i32::from_ne_bytes(out.to_ne_bytes()) as i64); - None + let out = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); + hand_mem.write_fixed(args[2], i32::from_ne_bytes(out.to_ne_bytes()) as i64)?; + Ok(None) }); cpu!(strf64 => fn(args, hand_mem) { - let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let out: f64 = s.parse().unwrap(); - hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes())); - None + hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes()))?; + Ok(None) }); cpu!(boolf64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]) as f64; - hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes())); - None + let out = hand_mem.read_fixed(args[0])? as f64; + hand_mem.write_fixed(args[2], i64::from_ne_bytes(out.to_ne_bytes()))?; + Ok(None) }); cpu!(i8f32 => fn(args, hand_mem) { - let num = hand_mem.read_fixed(args[0]) as f32; + let num = hand_mem.read_fixed(args[0])? as f32; let out = i32::from_ne_bytes(num.to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i16f32 => fn(args, hand_mem) { - let num = hand_mem.read_fixed(args[0]) as f32; + let num = hand_mem.read_fixed(args[0])? as f32; let out = i32::from_ne_bytes(num.to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i32f32 => fn(args, hand_mem) { - let num = hand_mem.read_fixed(args[0]) as f32; + let num = hand_mem.read_fixed(args[0])? as f32; let out = i32::from_ne_bytes(num.to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i64f32 => fn(args, hand_mem) { - let num = hand_mem.read_fixed(args[0]) as f32; + let num = hand_mem.read_fixed(args[0])? as f32; let out = i32::from_ne_bytes(num.to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f64f32 => fn(args, hand_mem) { - let num = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()) as f32; + let num = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()) as f32; let out = i32::from_ne_bytes(num.to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(strf32 => fn(args, hand_mem) { - let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let num: f32 = s.parse().unwrap(); let out = i32::from_ne_bytes(num.to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(boolf32 => fn(args, hand_mem) { - let num = hand_mem.read_fixed(args[0]) as f32; + let num = hand_mem.read_fixed(args[0])? as f32; let out = i32::from_ne_bytes(num.to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i8i64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i16i64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i32i64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f64i64 => fn(args, hand_mem) { - let out = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f32i64 => fn(args, hand_mem) { - let out = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(stri64 => fn(args, hand_mem) { - let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let out: i64 = s.parse().unwrap(); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(booli64 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i8i32 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i16i32 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i64i32 => fn(args, hand_mem) { - let out = (hand_mem.read_fixed(args[0]) as i32) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (hand_mem.read_fixed(args[0])? as i32) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f64i32 => fn(args, hand_mem) { - let out = (f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()) as i32) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()) as i32) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f32i32 => fn(args, hand_mem) { - let out = (f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()) as i32) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()) as i32) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(stri32 => fn(args, hand_mem) { - let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let num: i32 = s.parse().unwrap(); let out = num as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(booli32 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i8i16 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i32i16 => fn(args, hand_mem) { - let out = (hand_mem.read_fixed(args[0]) as i16) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (hand_mem.read_fixed(args[0])? as i16) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i64i16 => fn(args, hand_mem) { - let out = (hand_mem.read_fixed(args[0]) as i16) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (hand_mem.read_fixed(args[0])? as i16) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f64i16 => fn(args, hand_mem) { - let out = (f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()) as i16) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()) as i16) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f32i16 => fn(args, hand_mem) { - let out = (f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()) as i16) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()) as i16) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(stri16 => fn(args, hand_mem) { - let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let num: i16 = s.parse().unwrap(); let out = num as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(booli16 => fn(args, hand_mem) { - let out = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], out); - None + let out = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i16i8 => fn(args, hand_mem) { - let out = (hand_mem.read_fixed(args[0]) as i8) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (hand_mem.read_fixed(args[0])? as i8) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i32i8 => fn(args, hand_mem) { - let out = (hand_mem.read_fixed(args[0]) as i8) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (hand_mem.read_fixed(args[0])? as i8) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i64i8 => fn(args, hand_mem) { - let out = (hand_mem.read_fixed(args[0]) as i8) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (hand_mem.read_fixed(args[0])? as i8) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f64i8 => fn(args, hand_mem) { - let out = (f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()) as i8) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()) as i8) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f32i8 => fn(args, hand_mem) { - let out = (f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()) as i8) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()) as i8) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(stri8 => fn(args, hand_mem) { - let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let num: i8 = s.parse().unwrap(); let out = num as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(booli8 => fn(args, hand_mem) { - let out = (hand_mem.read_fixed(args[0]) as i8) as i64; - hand_mem.write_fixed(args[2], out); - None + let out = (hand_mem.read_fixed(args[0])? as i8) as i64; + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i8bool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; let out = if a != 0 { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i16bool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; let out = if a != 0 { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i32bool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; let out = if a != 0 { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i64bool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); + let a = hand_mem.read_fixed(args[0])?; let out = if a != 0 { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f64bool => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = if a != 0.0 { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(f32bool => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); let out = if a != 0.0 { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(strbool => fn(args, hand_mem) { - let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let s = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let out = if s == "true" { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(i8str => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; let a_str = a.to_string(); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str))?; + Ok(None) }); cpu!(i16str => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; let a_str = a.to_string(); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str))?; + Ok(None) }); cpu!(i32str => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; let a_str = a.to_string(); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str))?; + Ok(None) }); cpu!(i64str => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); + let a = hand_mem.read_fixed(args[0])?; let a_str = a.to_string(); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str))?; + Ok(None) }); cpu!(f64str => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let a_str = a.to_string(); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str))?; + Ok(None) }); cpu!(f32str => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); let a_str = a.to_string(); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str))?; + Ok(None) }); cpu!(boolstr => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); + let a = hand_mem.read_fixed(args[0])?; let a_str = if a == 1 { "true" } else { "false" }; - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&a_str))?; + Ok(None) }); // Arithmetic opcodes cpu!(addi8 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i8; - let b = rb.read_fixed(1) as i8; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i8; + let b = rb.read_fixed(1)? as i8; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && a > std::i8::MAX - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && a < std::i8::MIN - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a + b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a + b) as i64)?; + Ok(None) }); cpu!(addi16 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i16; - let b = rb.read_fixed(1) as i16; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i16; + let b = rb.read_fixed(1)? as i16; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && a > std::i16::MAX - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && a < std::i16::MIN - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a + b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a + b) as i64)?; + Ok(None) }); cpu!(addi32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i32; - let b = rb.read_fixed(1) as i32; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i32; + let b = rb.read_fixed(1)? as i32; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && a > std::i32::MAX - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && a < std::i32::MIN - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a + b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a + b) as i64)?; + Ok(None) }); cpu!(addi64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i64; - let b = rb.read_fixed(1) as i64; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i64; + let b = rb.read_fixed(1)? as i64; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && a > std::i64::MAX - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && a < std::i64::MIN - b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a + b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a + b) as i64)?; + Ok(None) }); cpu!(addf32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f32::from_ne_bytes((ra.read_fixed(1) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((rb.read_fixed(1) as i32).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f32::from_ne_bytes((ra.read_fixed(1)? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((rb.read_fixed(1)? as i32).to_ne_bytes()); let out = a + b; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f32::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f32::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i32::from_ne_bytes(out.to_ne_bytes()) as i64; - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(addf64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f64::from_ne_bytes(ra.read_fixed(1).to_ne_bytes()); - let b = f64::from_ne_bytes(rb.read_fixed(1).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f64::from_ne_bytes(ra.read_fixed(1)?.to_ne_bytes()); + let b = f64::from_ne_bytes(rb.read_fixed(1)?.to_ne_bytes()); let out = a + b; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f64::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f64::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i64::from_ne_bytes(out.to_ne_bytes()); - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(subi8 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i8; - let b = rb.read_fixed(1) as i8; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i8; + let b = rb.read_fixed(1)? as i8; + hand_mem.init_fractal(args[2])?; if a > 0 && b < 0 && a > std::i8::MAX + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 0 && a < std::i8::MIN + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a - b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a - b) as i64)?; + Ok(None) }); cpu!(subi16 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i16; - let b = rb.read_fixed(1) as i16; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i16; + let b = rb.read_fixed(1)? as i16; + hand_mem.init_fractal(args[2])?; if a > 0 && b < 0 && a > std::i16::MAX + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 0 && a < std::i16::MIN + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a - b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a - b) as i64)?; + Ok(None) }); cpu!(subi32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i32; - let b = rb.read_fixed(1) as i32; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i32; + let b = rb.read_fixed(1)? as i32; + hand_mem.init_fractal(args[2])?; if a > 0 && b < 0 && a > std::i32::MAX + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 0 && a < std::i32::MIN + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a - b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a - b) as i64)?; + Ok(None) }); cpu!(subi64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i64; - let b = rb.read_fixed(1) as i64; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i64; + let b = rb.read_fixed(1)? as i64; + hand_mem.init_fractal(args[2])?; if a > 0 && b < 0 && a > std::i64::MAX + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 0 && a < std::i64::MIN + b { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], a - b); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], a - b)?; + Ok(None) }); cpu!(subf32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f32::from_ne_bytes((ra.read_fixed(1) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((rb.read_fixed(1) as i32).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f32::from_ne_bytes((ra.read_fixed(1)? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((rb.read_fixed(1)? as i32).to_ne_bytes()); let out = a - b; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f32::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f32::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i32::from_ne_bytes(out.to_ne_bytes()) as i64; - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(subf64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f64::from_ne_bytes(ra.read_fixed(1).to_ne_bytes()); - let b = f64::from_ne_bytes(rb.read_fixed(1).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f64::from_ne_bytes(ra.read_fixed(1)?.to_ne_bytes()); + let b = f64::from_ne_bytes(rb.read_fixed(1)?.to_ne_bytes()); let out = a - b; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f64::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f64::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i64::from_ne_bytes(out.to_ne_bytes()); - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(negi8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; let out = (0 - a) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(negi16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; let out = (0 - a) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(negi32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; let out = (0 - a) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(negi64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); + let a = hand_mem.read_fixed(args[0])?; let out = 0 - a; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(negf32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); let out = i32::from_ne_bytes((0.0 - a).to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(negf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes((0.0 - a).to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(absi8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; let out = a.abs() as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(absi16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; let out = a.abs() as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(absi32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; let out = a.abs() as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(absi64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); + let a = hand_mem.read_fixed(args[0])?; let out = a.abs(); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(absf32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); let out = i32::from_ne_bytes(a.abs().to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(absf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.abs().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(muli8 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i8; - let b = rb.read_fixed(1) as i8; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i8; + let b = rb.read_fixed(1)? as i8; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && (a as f64) > (std::i8::MAX as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && (a as f64) < (std::i8::MIN as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a * b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a * b) as i64)?; + Ok(None) }); cpu!(muli16 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i16; - let b = rb.read_fixed(1) as i16; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i16; + let b = rb.read_fixed(1)? as i16; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && (a as f64) > (std::i16::MAX as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && (a as f64) < (std::i16::MIN as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a * b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a * b) as i64)?; + Ok(None) }); cpu!(muli32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i32; - let b = rb.read_fixed(1) as i32; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i32; + let b = rb.read_fixed(1)? as i32; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && (a as f64) > (std::i32::MAX as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && (a as f64) < (std::i32::MIN as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a * b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a * b) as i64)?; + Ok(None) }); cpu!(muli64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i64; - let b = rb.read_fixed(1) as i64; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i64; + let b = rb.read_fixed(1)? as i64; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 0 && (a as f64) > (std::i64::MAX as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b < 0 && (a as f64) < (std::i64::MIN as f64) / (b as f64) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], a * b); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], a * b)?; + Ok(None) }); cpu!(mulf32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f32::from_ne_bytes((ra.read_fixed(1) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((rb.read_fixed(1) as i32).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f32::from_ne_bytes((ra.read_fixed(1)? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((rb.read_fixed(1)? as i32).to_ne_bytes()); let out = a * b; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f32::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f32::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i32::from_ne_bytes(out.to_ne_bytes()) as i64; - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(mulf64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f64::from_ne_bytes(ra.read_fixed(1).to_ne_bytes()); - let b = f64::from_ne_bytes(rb.read_fixed(1).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f64::from_ne_bytes(ra.read_fixed(1)?.to_ne_bytes()); + let b = f64::from_ne_bytes(rb.read_fixed(1)?.to_ne_bytes()); let out = a * b; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f64::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f64::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i64::from_ne_bytes(out.to_ne_bytes()); - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(divi8 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i8; - let b = rb.read_fixed(1) as i8; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i8; + let b = rb.read_fixed(1)? as i8; + hand_mem.init_fractal(args[2])?; if b == 0 { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a / b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a / b) as i64)?; + Ok(None) }); cpu!(divi16 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i16; - let b = rb.read_fixed(1) as i16; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i16; + let b = rb.read_fixed(1)? as i16; + hand_mem.init_fractal(args[2])?; if b == 0 { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a / b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a / b) as i64)?; + Ok(None) }); cpu!(divi32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i32; - let b = rb.read_fixed(1) as i32; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i32; + let b = rb.read_fixed(1)? as i32; + hand_mem.init_fractal(args[2])?; if b == 0 { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], (a / b) as i64); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], (a / b) as i64)?; + Ok(None) }); cpu!(divi64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i64; - let b = rb.read_fixed(1) as i64; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i64; + let b = rb.read_fixed(1)? as i64; + hand_mem.init_fractal(args[2])?; if b == 0 { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], a / b); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], a / b)?; + Ok(None) }); cpu!(divf32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f32::from_ne_bytes((ra.read_fixed(1) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((rb.read_fixed(1) as i32).to_ne_bytes()); - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f32::from_ne_bytes((ra.read_fixed(1)? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((rb.read_fixed(1)? as i32).to_ne_bytes()); + hand_mem.init_fractal(args[2])?; if b == 0.0 { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero"))?; + return Ok(None); } let out = a / b; if out == std::f32::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f32::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i32::from_ne_bytes(out.to_ne_bytes()) as i64; - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(divf64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f64::from_ne_bytes(ra.read_fixed(1).to_ne_bytes()); - let b = f64::from_ne_bytes(rb.read_fixed(1).to_ne_bytes()); - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f64::from_ne_bytes(ra.read_fixed(1)?.to_ne_bytes()); + let b = f64::from_ne_bytes(rb.read_fixed(1)?.to_ne_bytes()); + hand_mem.init_fractal(args[2])?; if b == 0.0 { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("divide-by-zero"))?; + return Ok(None); } let out = a / b; if out == std::f64::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f64::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i64::from_ne_bytes(out.to_ne_bytes()); - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(modi8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = (a % b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(modi16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = (a % b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(modi32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = (a % b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(modi64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = a % b; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(powi8 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i8; - let b = rb.read_fixed(1) as i8; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i8; + let b = rb.read_fixed(1)? as i8; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 1 && (a as f64) > f64::powf(std::i8::MAX as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 1 && (a as f64) < f64::powf(std::i8::MIN as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); + hand_mem.push_fixed(args[2], 1)?; let out = if b < 0 { 0i64 } else { i8::pow(a, b as u32) as i64 }; - hand_mem.push_fixed(args[2], out); - None + hand_mem.push_fixed(args[2], out)?; + Ok(None) }); cpu!(powi16 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i16; - let b = rb.read_fixed(1) as i16; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i16; + let b = rb.read_fixed(1)? as i16; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 1 && (a as f64) > f64::powf(std::i16::MAX as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 1 && (a as f64) < f64::powf(std::i16::MIN as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); + hand_mem.push_fixed(args[2], 1)?; let out = if b < 0 { 0i64 } else { i16::pow(a, b as u32) as i64 }; - hand_mem.push_fixed(args[2], out); - None + hand_mem.push_fixed(args[2], out)?; + Ok(None) }); cpu!(powi32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i32; - let b = rb.read_fixed(1) as i32; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i32; + let b = rb.read_fixed(1)? as i32; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 1 && (a as f64) > f64::powf(std::i32::MAX as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 1 && (a as f64) < f64::powf(std::i32::MIN as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); + hand_mem.push_fixed(args[2], 1)?; let out = if b < 0 { 0i64 } else { i32::pow(a, b as u32) as i64 }; - hand_mem.push_fixed(args[2], out); - None + hand_mem.push_fixed(args[2], out)?; + Ok(None) }); cpu!(powi64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = ra.read_fixed(1) as i64; - let b = rb.read_fixed(1) as i64; - hand_mem.init_fractal(args[2]); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = ra.read_fixed(1)? as i64; + let b = rb.read_fixed(1)? as i64; + hand_mem.init_fractal(args[2])?; if a > 0 && b > 1 && (a as f64) > f64::powf(std::i64::MAX as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if a < 0 && b > 1 && (a as f64) < f64::powf(std::i64::MIN as f64, 1.0 / (b as f64)) { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } - hand_mem.push_fixed(args[2], 1); + hand_mem.push_fixed(args[2], 1)?; let out = if b < 0 { 0i64 } else { i64::pow(a, b as u32) as i64 }; - hand_mem.push_fixed(args[2], out); - None + hand_mem.push_fixed(args[2], out)?; + Ok(None) }); cpu!(powf32 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f32::from_ne_bytes((ra.read_fixed(1) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((rb.read_fixed(1) as i32).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f32::from_ne_bytes((ra.read_fixed(1)? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((rb.read_fixed(1)? as i32).to_ne_bytes()); let out = f32::powf(a, b); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f32::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f32::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i32::from_ne_bytes(out.to_ne_bytes()) as i64; - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(powf64 => fn(args, hand_mem) { - let ra = hand_mem.read_fractal(args[0]); - let rb = hand_mem.read_fractal(args[1]); - if ra.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &ra); - return None; - } - if rb.read_fixed(0) == 0 { - hand_mem.write_fractal(args[2], &rb); - return None; - } - let a = f64::from_ne_bytes(ra.read_fixed(1).to_ne_bytes()); - let b = f64::from_ne_bytes(rb.read_fixed(1).to_ne_bytes()); + let ra = hand_mem.read_fractal(args[0])?; + let rb = hand_mem.read_fractal(args[1])?; + if ra.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &ra)?; + return Ok(None); + } + if rb.read_fixed(0)? == 0 { + hand_mem.write_fractal(args[2], &rb)?; + return Ok(None); + } + let a = f64::from_ne_bytes(ra.read_fixed(1)?.to_ne_bytes()); + let b = f64::from_ne_bytes(rb.read_fixed(1)?.to_ne_bytes()); let out = f64::powf(a, b); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if out == std::f64::INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("overflow"))?; + return Ok(None); } if out == std::f64::NEG_INFINITY { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow")); - return None; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("underflow"))?; + return Ok(None); } let num = i64::from_ne_bytes(out.to_ne_bytes()); - hand_mem.push_fixed(args[2], 1); - hand_mem.push_fixed(args[2], num); - None + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], num)?; + Ok(None) }); cpu!(sqrtf32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); let out = i32::from_ne_bytes(f32::sqrt(a).to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(sqrtf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(f64::sqrt(a).to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); // Boolean and bitwise opcodes cpu!(andi8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = (a & b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(andi16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = (a & b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(andi32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = (a & b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(andi64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = a & b; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(andbool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let a_bool = if a == 1 { true } else { false }; let b_bool = if b == 1 { true } else { false }; let out = if a_bool & b_bool { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ori8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = (a | b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ori16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = (a | b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ori32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = (a | b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ori64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = a | b; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(orbool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let a_bool = if a == 1 { true } else { false }; let b_bool = if b == 1 { true } else { false }; let out = if a_bool | b_bool { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xori8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = (a ^ b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xori16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = (a ^ b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xori32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = (a ^ b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xori64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = a ^ b; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xorbool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let a_bool = if a == 1 { true } else { false }; let b_bool = if b == 1 { true } else { false }; let out = if a_bool ^ b_bool { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(noti8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; let out = !a as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(noti16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; let out = !a as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(noti32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; let out = !a as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(noti64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); + let a = hand_mem.read_fixed(args[0])?; let out = !a; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(notbool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); + let a = hand_mem.read_fixed(args[0])?; let a_bool = if a == 1 { true } else { false }; let out = if !a_bool { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nandi8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = !(a & b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nandi16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = !(a & b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nandi32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = !(a & b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nandi64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = !(a & b); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nandboo => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let a_bool = if a == 1 { true } else { false }; let b_bool = if b == 1 { true } else { false }; let out = if !(a_bool & b_bool) { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nori8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = !(a | b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nori16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = !(a | b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nori32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = !(a | b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(nori64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = !(a | b); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(norbool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let a_bool = if a == 1 { true } else { false }; let b_bool = if b == 1 { true } else { false }; let out = if !(a_bool | b_bool) { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xnori8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = !(a ^ b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xnori16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = !(a ^ b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xnori32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = !(a ^ b) as i64; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xnori64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = !(a ^ b); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(xnorboo => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let a_bool = if a == 1 { true } else { false }; let b_bool = if b == 1 { true } else { false }; let out = if !(a_bool ^ b_bool) { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); // Equality and order opcodes cpu!(eqi8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a == b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(eqi16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = if a == b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(eqi32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = if a == b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(eqi64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = if a == b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(eqf32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1])? as i32).to_ne_bytes()); let out = if a == b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(eqf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); - let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); + let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1])?.to_ne_bytes()); let out = if a == b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(eqstr => fn(args, hand_mem) { - let a_pascal_string = hand_mem.read_fractal(args[0]); - let b_pascal_string = hand_mem.read_fractal(args[1]); + let a_pascal_string = hand_mem.read_fractal(args[0])?; + let b_pascal_string = hand_mem.read_fractal(args[1])?; let out = if args[0] < 0 || args[1] < 0 { // Special path for global memory stored strings, they aren't represented the same way - let a_str = HandlerMemory::fractal_to_string(a_pascal_string); - let b_str = HandlerMemory::fractal_to_string(b_pascal_string); + let a_str = HandlerMemory::fractal_to_string(a_pascal_string)?; + let b_str = HandlerMemory::fractal_to_string(b_pascal_string)?; if a_str == b_str { 1i64 } else { 0i64 } } else if a_pascal_string == b_pascal_string { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(eqbool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a == b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqi8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a != b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqi16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = if a != b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqi32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = if a != b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqi64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = if a != b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqf32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1])? as i32).to_ne_bytes()); let out = if a != b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); - let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); + let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1])?.to_ne_bytes()); let out = if a != b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqstr => fn(args, hand_mem) { - let a_pascal_string = hand_mem.read_fractal(args[0]); - let b_pascal_string = hand_mem.read_fractal(args[1]); + let a_pascal_string = hand_mem.read_fractal(args[0])?; + let b_pascal_string = hand_mem.read_fractal(args[1])?; let out = if a_pascal_string != b_pascal_string { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(neqbool => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a != b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(lti8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a < b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(lti16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = if a < b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(lti32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = if a < b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(lti64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = if a < b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltf32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1])? as i32).to_ne_bytes()); let out = if a < b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); - let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); + let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1])?.to_ne_bytes()); let out = if a < b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltstr => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let out = if a_str < b_str { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltei8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a <= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltei16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = if a <= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltei32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = if a <= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltei64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = if a <= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltef32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1])? as i32).to_ne_bytes()); let out = if a <= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltef64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); - let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); + let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1])?.to_ne_bytes()); let out = if a <= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(ltestr => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let out = if a_str <= b_str { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gti8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a > b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gti16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = if a > b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gti32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = if a > b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gti64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = if a > b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtf32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1])? as i32).to_ne_bytes()); let out = if a > b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); - let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); + let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1])?.to_ne_bytes()); let out = if a > b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtstr => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let out = if a_str > b_str { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtei8 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i8; - let b = hand_mem.read_fixed(args[1]) as i8; + let a = hand_mem.read_fixed(args[0])? as i8; + let b = hand_mem.read_fixed(args[1])? as i8; let out = if a >= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtei16 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i16; - let b = hand_mem.read_fixed(args[1]) as i16; + let a = hand_mem.read_fixed(args[0])? as i16; + let b = hand_mem.read_fixed(args[1])? as i16; let out = if a >= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtei32 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]) as i32; - let b = hand_mem.read_fixed(args[1]) as i32; + let a = hand_mem.read_fixed(args[0])? as i32; + let b = hand_mem.read_fixed(args[1])? as i32; let out = if a >= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtei64 => fn(args, hand_mem) { - let a = hand_mem.read_fixed(args[0]); - let b = hand_mem.read_fixed(args[1]); + let a = hand_mem.read_fixed(args[0])?; + let b = hand_mem.read_fixed(args[1])?; let out = if a >= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtef32 => fn(args, hand_mem) { - let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0]) as i32).to_ne_bytes()); - let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1]) as i32).to_ne_bytes()); + let a = f32::from_ne_bytes((hand_mem.read_fixed(args[0])? as i32).to_ne_bytes()); + let b = f32::from_ne_bytes((hand_mem.read_fixed(args[1])? as i32).to_ne_bytes()); let out = if a >= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtef64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); - let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); + let b = f64::from_ne_bytes(hand_mem.read_fixed(args[1])?.to_ne_bytes()); let out = if a >= b { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(gtestr => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let out = if a_str >= b_str { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); // String opcodes cpu!(catstr => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let out_str = format!("{}{}", a_str, b_str); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str))?; + Ok(None) }); cpu!(split => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let out_hms = a_str.split(&b_str).map(|out_str| HandlerMemory::str_to_fractal(&out_str)); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; for out in out_hms { - hand_mem.push_fractal(args[2], out); + hand_mem.push_fractal(args[2], out)?; } - None + Ok(None) }); cpu!(repstr => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let n = hand_mem.read_fixed(args[1]); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let n = hand_mem.read_fixed(args[1])?; let out_str = a_str.repeat(n as usize); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str))?; + Ok(None) }); cpu!(matches => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); - let b_regex = Regex::new(&b_str).unwrap(); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; + let b_regex = Regex::new(&b_str).map_err(|regex_err| VMError::Other(format!("Bad regex construction: {}", regex_err)))?; let out = if b_regex.is_match(&a_str) { 1i64 } else { 0i64 }; - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(indstr => fn(args, hand_mem) { - let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let a_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let b_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let out_option = a_str.find(&b_str); - hand_mem.init_fractal(args[2]); - if out_option.is_none() { - hand_mem.push_fixed(args[2], 0i64); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal("substring not found")); - } else { - hand_mem.push_fixed(args[2], 1i64); - let out = out_option.unwrap() as i64; - hand_mem.push_fixed(args[2], out); + hand_mem.init_fractal(args[2])?; + match out_option { + Some(out) => { + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_fixed(args[2], out as i64)?; + }, + None => { + hand_mem.push_fixed(args[2], 0)?; + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal("substring not found"))?; + }, } - None + Ok(None) }); cpu!(lenstr => fn(args, hand_mem) { - let pascal_string = hand_mem.read_fractal(args[0]); - let val = pascal_string.read_fixed(0); - hand_mem.write_fixed(args[2], val); - None + let pascal_string = hand_mem.read_fractal(args[0])?; + let val = pascal_string.read_fixed(0)?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(trim => fn(args, hand_mem) { - let in_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let in_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let out_str = in_str.trim(); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str))?; + Ok(None) }); // Array opcodes @@ -2170,64 +2173,64 @@ pub static OPCODES: Lazy> = Lazy::new(|| { // args[2] is the register address // args[0] point to an array in memory // args[1] is the address within the array to register - let inner_addr = hand_mem.read_fixed(args[1]); - hand_mem.register_out(args[0], inner_addr as usize, args[2]); - None + let inner_addr = hand_mem.read_fixed(args[1])?; + hand_mem.register_out(args[0], inner_addr as usize, args[2])?; + Ok(None) }); cpu!(copyfrom => fn(args, hand_mem) { // args = [arr_addr, arr_idx_addr, outer_addr] // copy data from outer_addr to inner_addr of the array in reg_addr // The array index instead of inner address is provided to keep interaction with the js-runtime // sane. - let inner_addr = hand_mem.read_fixed(args[1]); - hand_mem.register_out(args[0], inner_addr as usize, args[2]); - None + let inner_addr = hand_mem.read_fixed(args[1])?; + hand_mem.register_out(args[0], inner_addr as usize, args[2])?; + Ok(None) }); cpu!(copytof => fn(args, hand_mem) { // args = [arr_addr, inner_addr, outer_addr] // copy data from outer_addr to inner_addr in arr_addr - let inner = hand_mem.read_fixed(args[1]); - hand_mem.register_in(args[2], args[0], inner); - None + let inner = hand_mem.read_fixed(args[1])?; + hand_mem.register_in(args[2], args[0], inner)?; + Ok(None) }); cpu!(copytov => fn(args, hand_mem) { // args = [arr_addr, inner_addr, outer_addr] // copy data from outer_addr to inner_addr in arr_addr - let inner = hand_mem.read_fixed(args[1]); - hand_mem.register_in(args[2], args[0], inner); - None + let inner = hand_mem.read_fixed(args[1])?; + hand_mem.register_in(args[2], args[0], inner)?; + Ok(None) }); cpu!(lenarr => fn(args, hand_mem) { - let arr = hand_mem.read_fractal(args[0]); + let arr = hand_mem.read_fractal(args[0])?; let len = arr.len() as i64; - hand_mem.write_fixed(args[2], len); - None + hand_mem.write_fixed(args[2], len)?; + Ok(None) }); cpu!(indarrf => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[1]); - let mem = hand_mem.read_fractal(args[0]); + let val = hand_mem.read_fixed(args[1])?; + let mem = hand_mem.read_fractal(args[0])?; let len = mem.len(); let mut idx = -1i64; for i in 0..len { - let check = mem.read_fixed(i); + let check = mem.read_fixed(i)?; if val == check { idx = i as i64; break; } } - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if idx == -1i64 { - hand_mem.push_fixed(args[2], 0i64); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal("element not found")); + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal("element not found"))?; } else { - hand_mem.push_fixed(args[2], 1i64); - hand_mem.push_fixed(args[2], idx); + hand_mem.push_fixed(args[2], 1i64)?; + hand_mem.push_fixed(args[2], idx)?; } - None + Ok(None) }); cpu!(indarrv => fn(args, hand_mem) { - let val = hand_mem.read_fractal(args[1]); - let fractal = hand_mem.read_fractal(args[0]); + let val = hand_mem.read_fractal(args[1])?; + let fractal = hand_mem.read_fractal(args[0])?; let mut idx: Option = None; for i in 0..fractal.len() { if let (check, true) = hand_mem.read_from_fractal(&fractal, i) { @@ -2249,119 +2252,125 @@ pub static OPCODES: Lazy> = Lazy::new(|| { } // the else branch originally just had `continue` } - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if let Some(idx) = idx { - hand_mem.push_fixed(args[2], 1i64); - hand_mem.push_fixed(args[2], idx); + hand_mem.push_fixed(args[2], 1i64)?; + hand_mem.push_fixed(args[2], idx)?; } else { - hand_mem.push_fixed(args[2], 0i64); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal("element not found")); + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal("element not found"))?; } - None + Ok(None) }); cpu!(join => fn(args, hand_mem) { - let sep_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); - let fractal = hand_mem.read_fractal(args[0]); + let sep_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; + let fractal = hand_mem.read_fractal(args[0])?; let mut strs = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { match hand_mem.read_from_fractal(&fractal, i) { (data, true) => { - let v_str = HandlerMemory::fractal_to_string(data); + let v_str = HandlerMemory::fractal_to_string(data)?; strs.push(v_str); }, (_, false) => todo!("handle joining non-fractal strings I think?"), } } let out_str = strs.join(&sep_str); - hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str)); - None + hand_mem.write_fractal(args[2], &HandlerMemory::str_to_fractal(&out_str))?; + Ok(None) }); cpu!(pusharr => fn(args, hand_mem) { - let val_size = hand_mem.read_fixed(args[2]); + let val_size = hand_mem.read_fixed(args[2])?; if val_size == 0 { - hand_mem.push_register(args[0], args[1]); + hand_mem.push_register(args[0], args[1])?; } else { - let val = hand_mem.read_fixed(args[1]); - hand_mem.push_fixed(args[0], val); + let val = hand_mem.read_fixed(args[1])?; + hand_mem.push_fixed(args[0], val)?; } - None + Ok(None) }); cpu!(poparr => fn(args, hand_mem) { let last = hand_mem.pop(args[0]); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; match last { Ok(record) => { - hand_mem.push_fixed(args[2], 1i64); - hand_mem.push_register_out(args[2], &record, 0); + hand_mem.push_fixed(args[2], 1i64)?; + hand_mem.push_register_out(args[2], &record, 0)?; }, - Err(error_string) => { - hand_mem.push_fixed(args[2], 0i64); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&error_string)); + Err(error) => { + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&format!("{}", error)))?; }, } - None + Ok(None) }); cpu!(delindx => fn(args, hand_mem) { - let idx = hand_mem.read_fixed(args[1]) as usize; + let idx = hand_mem.read_fixed(args[1])? as usize; let el = hand_mem.delete(args[0], idx); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; match el { Ok(record) => { - hand_mem.push_fixed(args[2], 1i64); - hand_mem.push_register_out(args[2], &record, 0); + hand_mem.push_fixed(args[2], 1i64)?; + hand_mem.push_register_out(args[2], &record, 0)?; }, - Err(error_string) => { - hand_mem.push_fixed(args[2], 0i64); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&error_string)); + Err(error) => { + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&format!("{}", error)))?; }, } - None + Ok(None) }); cpu!(newarr => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - None + hand_mem.init_fractal(args[2])?; + Ok(None) }); io!(map => fn(args, mut hand_mem) { Box::pin(async move { - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); let mut mappers = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { - let mut hm = HandlerMemory::fork(hand_mem.clone()); - hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hm.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64); - mappers.push(subhandler.clone().run(hm).then(HandlerMemory::drop_parent_async)); + let mut hm = HandlerMemory::fork(hand_mem.clone())?; + hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hm.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64)?; + mappers.push({ + let subhandler = subhandler.clone(); + async move { + let hm = subhandler.run(hm).await?; + Ok(hm.drop_parent()?) + } + }); } let hms = join_all(mappers).await; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; for hm in hms { - hand_mem.join(hm); - hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START); + hand_mem.join(hm?)?; + hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START)?; } - hand_mem + Ok(hand_mem) }) }); unpred_cpu!(mapl => fn(args, mut hand_mem) { Box::pin(async move { - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; for i in 0..fractal.len() { - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hand_mem.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64); - hand_mem = subhandler.clone().run(hand_mem).await; - hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START); + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hand_mem.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64)?; + hand_mem = subhandler.clone().run(hand_mem).await?; + hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START)?; } - hand_mem + Ok(hand_mem) }) }); cpu!(reparr => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - let n = hand_mem.read_fixed(args[1]); + hand_mem.init_fractal(args[2])?; + let n = hand_mem.read_fixed(args[1])?; if n == 0 { - return None; + return Ok(None); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let mut is_fixed = true; let mut arr = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { @@ -2374,222 +2383,232 @@ pub static OPCODES: Lazy> = Lazy::new(|| { for _ in 0..n { for val in arr.iter() { if is_fixed { - hand_mem.push_fixed(args[2], val.read_fixed(0)); + hand_mem.push_fixed(args[2], val.read_fixed(0)?)?; } else { - hand_mem.push_fractal(args[2], val.clone()); + hand_mem.push_fractal(args[2], val.clone())?; } } } - None + Ok(None) }); io!(each => fn(args, hand_mem) { Box::pin(async move { if args[1] == NOP_ID { // each is expected to result in purely side effects - return hand_mem; + return Ok(hand_mem); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); let mut runners = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { - let mut hm = HandlerMemory::fork(hand_mem.clone()); - hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hm.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64); - runners.push(subhandler.clone().run(hm).then(HandlerMemory::drop_parent_async)); + let mut hm = HandlerMemory::fork(hand_mem.clone())?; + hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hm.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64)?; + runners.push({ + let subhandler = subhandler.clone(); + async move { + let hm = subhandler.run(hm).await?; + Ok(hm.drop_parent()?) + } + }); } - join_all(runners).await; - hand_mem + let runners: Vec> = join_all(runners).await; + runners.into_iter().collect::>>()?; + Ok(hand_mem) }) }); unpred_cpu!(eachl => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { // eachl is expected to result in purely side effects - return hand_mem; + return Ok(hand_mem); } - let n = hand_mem.read_fractal(args[0]).len(); + let n = hand_mem.read_fractal(args[0])?.len(); let subhandler = HandlerFragment::new(args[1], 0); for i in 0..n { - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hand_mem.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64); - hand_mem = subhandler.clone().run(hand_mem).await; + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hand_mem.write_fixed(CLOSURE_ARG_MEM_START + 2, i as i64)?; + hand_mem = subhandler.clone().run(hand_mem).await?; } - hand_mem + Ok(hand_mem) }) }); io!(find => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when finding"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let len = fractal.len(); let subhandler = HandlerFragment::new(args[1], 0); let mut finders = Vec::with_capacity(fractal.len()); for i in 0..len { - let mut hm = HandlerMemory::fork(hand_mem.clone()); - hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); + let mut hm = HandlerMemory::fork(hand_mem.clone())?; + hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; finders.push(subhandler.clone().run(hm)); } let hms = join_all(finders).await; let mut idx = None; for (i, hm) in hms.into_iter().enumerate() { - let val = hm.read_fixed(CLOSURE_ARG_MEM_START); - hm.drop_parent(); + let hm = hm?; + let val = hm.read_fixed(CLOSURE_ARG_MEM_START)?; + hm.drop_parent()?; if idx.is_none() && val == 1 { idx = Some(i); } } - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; if let Some(idx) = idx { - hand_mem.push_fixed(args[2], 1); - hand_mem.push_register_out(args[2], &fractal, idx); + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_register_out(args[2], &fractal, idx)?; } else { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("no element matches")); + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("no element matches"))?; } - hand_mem + Ok(hand_mem) }) }); unpred_cpu!(findl => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when finding"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); for i in 0..fractal.len() { - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hand_mem = subhandler.clone().run(hand_mem).await; - let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START); + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hand_mem = subhandler.clone().run(hand_mem).await?; + let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START)?; if val == 1 { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 1); - hand_mem.push_register_out(args[2], &fractal, i); - return hand_mem; + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_register_out(args[2], &fractal, i)?; + return Ok(hand_mem); } } - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("no element matches")); - hand_mem + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("no element matches"))?; + Ok(hand_mem) }) }); io!(some => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when checking if some"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); let mut somers = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { - let mut hm = HandlerMemory::fork(hand_mem.clone()); - hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); + let mut hm = HandlerMemory::fork(hand_mem.clone())?; + hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; somers.push(subhandler.clone().run(hm)); } let hms = join_all(somers).await; let mut ret_val = 0; for hm in hms { - let val = hm.read_fixed(CLOSURE_ARG_MEM_START); - hm.drop_parent(); + let hm = hm?; + let val = hm.read_fixed(CLOSURE_ARG_MEM_START)?; + hm.drop_parent()?; if val == 1 { ret_val = 1; } } - hand_mem.write_fixed(args[2], ret_val); - hand_mem + hand_mem.write_fixed(args[2], ret_val)?; + Ok(hand_mem) }) }); unpred_cpu!(somel => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when checking if some"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); for i in 0..fractal.len() { - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hand_mem = subhandler.clone().run(hand_mem).await; - let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START); + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hand_mem = subhandler.clone().run(hand_mem).await?; + let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START)?; if val == 1 { - hand_mem.write_fixed(args[2], 1); - return hand_mem; + hand_mem.write_fixed(args[2], 1)?; + return Ok(hand_mem); } } - hand_mem.write_fixed(args[2], 0); - hand_mem + hand_mem.write_fixed(args[2], 0)?; + Ok(hand_mem) }) }); io!(every => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when checking if every"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); let mut somers = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { - let mut hm = HandlerMemory::fork(hand_mem.clone()); - hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); + let mut hm = HandlerMemory::fork(hand_mem.clone())?; + hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; somers.push(subhandler.clone().run(hm)); } let hms = join_all(somers).await; let mut ret_val = 1; for hm in hms { - let val = hm.read_fixed(CLOSURE_ARG_MEM_START); - hm.drop_parent(); + let hm = hm?; + let val = hm.read_fixed(CLOSURE_ARG_MEM_START)?; + hm.drop_parent()?; if val == 0 { ret_val = 0; } } - hand_mem.write_fixed(args[2], ret_val); - hand_mem + hand_mem.write_fixed(args[2], ret_val)?; + Ok(hand_mem) }) }); unpred_cpu!(everyl => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when checking if every"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); for i in 0..fractal.len() { - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hand_mem = subhandler.clone().run(hand_mem).await; - let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START); + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hand_mem = subhandler.clone().run(hand_mem).await?; + let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START)?; if val == 0 { - hand_mem.write_fixed(args[2], 0); - return hand_mem; + hand_mem.write_fixed(args[2], 0)?; + return Ok(hand_mem); } } - hand_mem.write_fixed(args[2], 1); - hand_mem + hand_mem.write_fixed(args[2], 1)?; + Ok(hand_mem) }) }); cpu!(catarr => fn(args, hand_mem) { - let fractal1 = hand_mem.read_fractal(args[0]); - let fractal2 = hand_mem.read_fractal(args[1]); - hand_mem.init_fractal(args[2]); + let fractal1 = hand_mem.read_fractal(args[0])?; + let fractal2 = hand_mem.read_fractal(args[1])?; + hand_mem.init_fractal(args[2])?; for i in 0..fractal1.len() { - hand_mem.push_register_out(args[2], &fractal1, i); + hand_mem.push_register_out(args[2], &fractal1, i)?; } for i in 0..fractal2.len() { - hand_mem.push_register_out(args[2], &fractal2, i); + hand_mem.push_register_out(args[2], &fractal2, i)?; } - None + Ok(None) }); io!(reducep => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when reducing"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let mut vals = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { - let mut hm = HandlerMemory::new(None, 1); - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START); - HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut hm, 0); + let mut hm = HandlerMemory::new(None, 1)?; + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START)?; + HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut hm, 0)?; vals.push(hm); } let subhandler = HandlerFragment::new(args[1], 0); @@ -2600,16 +2619,17 @@ pub static OPCODES: Lazy> = Lazy::new(|| { let mut hm = hand_mem.clone(); let a = vals.remove(0); let b = vals.remove(0); - HandlerMemory::transfer(&a, 0, &mut hm, CLOSURE_ARG_MEM_START + 1); - HandlerMemory::transfer(&b, 0, &mut hm, CLOSURE_ARG_MEM_START + 2); + HandlerMemory::transfer(&a, 0, &mut hm, CLOSURE_ARG_MEM_START + 1)?; + HandlerMemory::transfer(&b, 0, &mut hm, CLOSURE_ARG_MEM_START + 2)?; reducers.push(subhandler.clone().run(hm)); } // Check if one of the records was skipped over this round, and if so, pop it into a // special field let maybe_hm = if vals.len() == 1 { Some(vals.remove(0)) } else { None }; let hms = join_all(reducers).await; - for mut hm in hms { - hm.register(0, CLOSURE_ARG_MEM_START, false); + for hm in hms { + let mut hm = hm?; + hm.register(0, CLOSURE_ARG_MEM_START, false)?; vals.push(hm); } if let Some(hm) = maybe_hm { @@ -2617,37 +2637,37 @@ pub static OPCODES: Lazy> = Lazy::new(|| { } } // There can be only one - HandlerMemory::transfer(&vals[0], 0, &mut hand_mem, args[2]); - hand_mem + HandlerMemory::transfer(&vals[0], 0, &mut hand_mem, args[2])?; + Ok(hand_mem) }) }); unpred_cpu!(reducel => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when reducing"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; if fractal.len() == 0 { - return hand_mem; + return Ok(hand_mem); } let mut vals = Vec::with_capacity(fractal.len()); for i in 0..fractal.len() { - let mut hm = HandlerMemory::new(None, 1); - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START); - HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut hm, 0); + let mut hm = HandlerMemory::new(None, 1)?; + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START)?; + HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut hm, 0)?; vals.push(hm); } let subhandler = HandlerFragment::new(args[1], 0); let mut cumulative = vals.remove(0); for i in 0..vals.len() { let current = &vals[i]; - HandlerMemory::transfer(&cumulative, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 1); - HandlerMemory::transfer(¤t, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 2); - hand_mem = subhandler.clone().run(hand_mem).await; - HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut cumulative, 0); + HandlerMemory::transfer(&cumulative, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 1)?; + HandlerMemory::transfer(¤t, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 2)?; + hand_mem = subhandler.clone().run(hand_mem).await?; + HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut cumulative, 0)?; } - HandlerMemory::transfer(&cumulative, 0, &mut hand_mem, args[2]); - hand_mem + HandlerMemory::transfer(&cumulative, 0, &mut hand_mem, args[2])?; + Ok(hand_mem) }) }); // io!(foldp => fn(args, mut hand_mem) { @@ -2707,140 +2727,141 @@ pub static OPCODES: Lazy> = Lazy::new(|| { unpred_cpu!(foldl => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when folding"); + return Err(VMError::InvalidNOP); } - let obj = hand_mem.read_fractal(args[0]); + let obj = hand_mem.read_fractal(args[0])?; let (arr, _) = hand_mem.read_from_fractal(&obj, 0); let mut vals = Vec::with_capacity(arr.len()); for i in 0..arr.len() { - let mut hm = HandlerMemory::new(None, 1); - hand_mem.register_from_fractal(CLOSURE_ARG_MEM_START, &arr, i); - HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut hm, 0); + let mut hm = HandlerMemory::new(None, 1)?; + hand_mem.register_from_fractal(CLOSURE_ARG_MEM_START, &arr, i)?; + HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut hm, 0)?; vals.push(hm); } let subhandler = HandlerFragment::new(args[1], 0); - hand_mem.register_out(args[0], 1, CLOSURE_ARG_MEM_START); - let mut cumulative = HandlerMemory::new(None, 1); - HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut cumulative, 0); + hand_mem.register_out(args[0], 1, CLOSURE_ARG_MEM_START)?; + let mut cumulative = HandlerMemory::new(None, 1)?; + HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut cumulative, 0)?; for i in 0..vals.len() { let current = &vals[i]; - HandlerMemory::transfer(&cumulative, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 1); - HandlerMemory::transfer(current, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 2); - hand_mem = subhandler.clone().run(hand_mem).await; - HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut cumulative, 0); + HandlerMemory::transfer(&cumulative, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 1)?; + HandlerMemory::transfer(current, 0, &mut hand_mem, CLOSURE_ARG_MEM_START + 2)?; + hand_mem = subhandler.clone().run(hand_mem).await?; + HandlerMemory::transfer(&hand_mem, CLOSURE_ARG_MEM_START, &mut cumulative, 0)?; } - hand_mem.register(args[2], CLOSURE_ARG_MEM_START, false); - hand_mem + hand_mem.register(args[2], CLOSURE_ARG_MEM_START, false)?; + Ok(hand_mem) }) }); io!(filter => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when filtering"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let len = fractal.len(); let subhandler = HandlerFragment::new(args[1], 0); let mut filters = Vec::with_capacity(len); for i in 0..len { - let mut hm = HandlerMemory::fork(hand_mem.clone()); - hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); + let mut hm = HandlerMemory::fork(hand_mem.clone())?; + hm.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; filters.push(subhandler.clone().run(hm)); } let hms = join_all(filters).await; let mut idxs = vec![]; for (i, hm) in hms.into_iter().enumerate() { - let val = hm.read_fixed(CLOSURE_ARG_MEM_START); - hm.drop_parent(); // this drops `hm` + let hm = hm?; + let val = hm.read_fixed(CLOSURE_ARG_MEM_START)?; + hm.drop_parent()?; if val == 1 { idxs.push(i); } } - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; for i in idxs { - hand_mem.push_register_out(args[2], &fractal, i); + hand_mem.push_register_out(args[2], &fractal, i)?; } - hand_mem + Ok(hand_mem) }) }); unpred_cpu!(filterl => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided when filtering"); + return Err(VMError::InvalidNOP); } - let fractal = hand_mem.read_fractal(args[0]); + let fractal = hand_mem.read_fractal(args[0])?; let len = fractal.len(); let subhandler = HandlerFragment::new(args[1], 0); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; for i in 0..len { - hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1); - hand_mem = subhandler.clone().run(hand_mem).await; - let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START); + hand_mem.register_out(args[0], i, CLOSURE_ARG_MEM_START + 1)?; + hand_mem = subhandler.clone().run(hand_mem).await?; + let val = hand_mem.read_fixed(CLOSURE_ARG_MEM_START)?; if val == 1 { - hand_mem.push_register_out(args[2], &fractal, i); + hand_mem.push_register_out(args[2], &fractal, i)?; } } - hand_mem + Ok(hand_mem) }) }); // Conditional opcode unpred_cpu!(condfn => fn(args, mut hand_mem) { Box::pin(async move { - let cond = hand_mem.read_fixed(args[0]); + let cond = hand_mem.read_fixed(args[0])?; let subhandler = HandlerFragment::new(args[1], 0); if cond == 1 { - hand_mem = subhandler.run(hand_mem).await; + hand_mem = subhandler.run(hand_mem).await?; } - hand_mem + Ok(hand_mem) }) }); // Std opcodes io!(execop => fn(args, mut hand_mem) { Box::pin(async move { - let cmd = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let cmd = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; let output = if cfg!(target_os = "windows") { Command::new("cmd").arg("/C").arg(cmd).output().await } else { Command::new("sh").arg("-c").arg(cmd).output().await }; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; match output { Err(e) => { - hand_mem.push_fixed(args[2], 127); - hand_mem.push_fractal(args[2], FractalMemory::new(vec![(0, 0)])); + hand_mem.push_fixed(args[2], 127)?; + hand_mem.push_fractal(args[2], FractalMemory::new(vec![(0, 0)]))?; let error_string = e.to_string(); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&error_string)); + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&error_string))?; }, Ok(output_res) => { let status_code = output_res.status.code().unwrap_or(127) as i64; - hand_mem.push_fixed(args[2], status_code); + hand_mem.push_fixed(args[2], status_code)?; let stdout_str = String::from_utf8(output_res.stdout).unwrap_or("".to_string()); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&stdout_str)); + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&stdout_str))?; let stderr_str = String::from_utf8(output_res.stderr).unwrap_or("".to_string()); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&stderr_str)); + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&stderr_str))?; }, }; - hand_mem + Ok(hand_mem) }) }); unpred_cpu!(waitop => fn(args, hand_mem) { Box::pin(async move { - let ms = hand_mem.read_fixed(args[0]) as u64; + let ms = hand_mem.read_fixed(args[0])? as u64; sleep(Duration::from_millis(ms)).await; - hand_mem + Ok(hand_mem) }) }); unpred_cpu!(syncop => fn(args, mut hand_mem) { Box::pin(async move { let closure = HandlerFragment::new(args[0], 0); - hand_mem.register(CLOSURE_ARG_MEM_START + 1, args[1], true); - hand_mem = closure.clone().run(hand_mem).await; - hand_mem.register(args[2], CLOSURE_ARG_MEM_START, true); - hand_mem + hand_mem.register(CLOSURE_ARG_MEM_START + 1, args[1], true)?; + hand_mem = closure.clone().run(hand_mem).await?; + hand_mem.register(args[2], CLOSURE_ARG_MEM_START, true)?; + Ok(hand_mem) }) }); @@ -2860,110 +2881,109 @@ pub static OPCODES: Lazy> = Lazy::new(|| { } else { req.body(Body::empty()) }; - if req_obj.is_err() { - return Err("Failed to construct request, invalid body provided".to_string()); - } else { - return Ok(HTTP_CLIENT.request(req_obj.unwrap())); + match req_obj { + Ok(req) => Ok(HTTP_CLIENT.request(req)), + Err(_) => Err("Failed to construct request, invalid body provided".to_string()), } } io!(httpreq => fn(args, mut hand_mem) { Box::pin(async move { - let req = hand_mem.read_fractal(args[0]); - let method = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&req, 0).0); - let url = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&req, 1).0); + let req = hand_mem.read_fractal(args[0])?; + let method = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&req, 0).0)?; + let url = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&req, 1).0)?; let headers = hand_mem.read_from_fractal(&req, 2).0; let mut out_headers = Vec::new(); for i in 0..headers.len() { let header = hand_mem.read_from_fractal(&headers, i).0; - let key = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&header, 0).0); - let val = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&header, 1).0); + let key = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&header, 0).0)?; + let val = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&header, 1).0)?; out_headers.push((key, val)); } - let body = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&req, 3).0); + let body = HandlerMemory::fractal_to_string(hand_mem.read_from_fractal(&req, 3).0)?; let out_body = if body.len() > 0 { Some(body) /* once told me... */ } else { None }; - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; let res = match __httpreq(method, url, out_headers, out_body) { Ok(res) => res, Err(estring) => { - hand_mem.push_fixed(args[2], 0i64); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&estring)); - return hand_mem; + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&estring))?; + return Ok(hand_mem); }, }; let mut res = match res.await { Ok(res) => res, Err(ee) => { - hand_mem.push_fixed(args[2], 0i64); + hand_mem.push_fixed(args[2], 0i64)?; hand_mem.push_fractal( args[2], HandlerMemory::str_to_fractal(format!("{}", ee).as_str()) - ); - return hand_mem; + )?; + return Ok(hand_mem); }, }; // The headers and body can fail, so check those first let headers = res.headers(); - let mut headers_hm = HandlerMemory::new(None, headers.len() as i64); - headers_hm.init_fractal(CLOSURE_ARG_MEM_START); + let mut headers_hm = HandlerMemory::new(None, headers.len() as i64)?; + headers_hm.init_fractal(CLOSURE_ARG_MEM_START)?; for (i, (key, val)) in headers.iter().enumerate() { let key_str = key.as_str(); let val_str = val.to_str(); match val_str { Ok(val_str) => { - headers_hm.init_fractal(i as i64); - headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(key_str)); - headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(val_str)); - headers_hm.push_register(CLOSURE_ARG_MEM_START, i as i64); + headers_hm.init_fractal(i as i64)?; + headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(key_str))?; + headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(val_str))?; + headers_hm.push_register(CLOSURE_ARG_MEM_START, i as i64)?; }, Err(_) => { - hand_mem.push_fixed(args[2], 0i64); + hand_mem.push_fixed(args[2], 0i64)?; hand_mem.push_fractal( args[2], HandlerMemory::str_to_fractal("Malformed headers encountered") - ); - return hand_mem; + )?; + return Ok(hand_mem); }, } } let body = match hyper::body::to_bytes(res.body_mut()).await { Ok(body) => body, Err(ee) => { - hand_mem.push_fixed(args[2], 0i64); + hand_mem.push_fixed(args[2], 0i64)?; hand_mem.push_fractal( args[2], HandlerMemory::str_to_fractal(format!("{}", ee).as_str()) - ); - return hand_mem; + )?; + return Ok(hand_mem); }, }; let body_str = match String::from_utf8(body.to_vec()) { Ok(body_str) => body_str, Err(ee) => { - hand_mem.push_fixed(args[2], 0i64); + hand_mem.push_fixed(args[2], 0i64)?; hand_mem.push_fractal( args[2], HandlerMemory::str_to_fractal(format!("{}", ee).as_str()) - ); - return hand_mem; + )?; + return Ok(hand_mem); }, }; - hand_mem.push_fixed(args[2], 1i64); - let mut res_hm = HandlerMemory::new(None, 3); - res_hm.init_fractal(0); - res_hm.push_fixed(0, res.status().as_u16() as i64); - HandlerMemory::transfer(&headers_hm, CLOSURE_ARG_MEM_START, &mut res_hm, CLOSURE_ARG_MEM_START); - res_hm.push_register(0, CLOSURE_ARG_MEM_START); - res_hm.push_fractal(0, HandlerMemory::str_to_fractal(&body_str)); - res_hm.push_fixed(0, 0i64); - HandlerMemory::transfer(&res_hm, 0, &mut hand_mem, CLOSURE_ARG_MEM_START); - hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START); - hand_mem + hand_mem.push_fixed(args[2], 1i64)?; + let mut res_hm = HandlerMemory::new(None, 3)?; + res_hm.init_fractal(0)?; + res_hm.push_fixed(0, res.status().as_u16() as i64)?; + HandlerMemory::transfer(&headers_hm, CLOSURE_ARG_MEM_START, &mut res_hm, CLOSURE_ARG_MEM_START)?; + res_hm.push_register(0, CLOSURE_ARG_MEM_START)?; + res_hm.push_fractal(0, HandlerMemory::str_to_fractal(&body_str))?; + res_hm.push_fixed(0, 0i64)?; + HandlerMemory::transfer(&res_hm, 0, &mut hand_mem, CLOSURE_ARG_MEM_START)?; + hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START)?; + Ok(hand_mem) }) }); - async fn http_listener(req: Request) -> Result, Infallible> { + async fn http_listener(req: Request) -> VMResult> { // Create a new event handler memory to add to the event queue - let mut event = HandlerMemory::new(None, 1); + let mut event = HandlerMemory::new(None, 1)?; // Grab the method let method_str = req.method().to_string(); let method = HandlerMemory::str_to_fractal(&method_str); @@ -2972,15 +2992,16 @@ pub static OPCODES: Lazy> = Lazy::new(|| { let url = HandlerMemory::str_to_fractal(&url_str); // Grab the headers let headers = req.headers(); - let mut headers_hm = HandlerMemory::new(None, headers.len() as i64); - headers_hm.init_fractal(CLOSURE_ARG_MEM_START); + let mut headers_hm = HandlerMemory::new(None, headers.len() as i64)?; + headers_hm.init_fractal(CLOSURE_ARG_MEM_START)?; for (i, (key, val)) in headers.iter().enumerate() { let key_str = key.as_str(); + // TODO: get rid of the potential panic here let val_str = val.to_str().unwrap(); - headers_hm.init_fractal(i as i64); - headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(key_str)); - headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(val_str)); - headers_hm.push_register(CLOSURE_ARG_MEM_START, i as i64); + headers_hm.init_fractal(i as i64)?; + headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(key_str))?; + headers_hm.push_fractal(i as i64, HandlerMemory::str_to_fractal(val_str))?; + headers_hm.push_register(CLOSURE_ARG_MEM_START, i as i64)?; } // Grab the body, if any let body_req = match hyper::body::to_bytes(req.into_body()).await { @@ -2992,32 +3013,33 @@ pub static OPCODES: Lazy> = Lazy::new(|| { )); } }; + // TODO: get rid of the potential panic here let body_str = str::from_utf8(&body_req).unwrap().to_string(); let body = HandlerMemory::str_to_fractal(&body_str); // Populate the event and emit it - event.init_fractal(0); - event.push_fractal(0, method); - event.push_fractal(0, url); + event.init_fractal(0)?; + event.push_fractal(0, method)?; + event.push_fractal(0, url)?; HandlerMemory::transfer( &headers_hm, CLOSURE_ARG_MEM_START, &mut event, CLOSURE_ARG_MEM_START, - ); - event.push_register(0, CLOSURE_ARG_MEM_START); - event.push_fractal(0, body); + )?; + event.push_register(0, CLOSURE_ARG_MEM_START)?; + event.push_fractal(0, body)?; // Generate a threadsafe raw ptr to the tx of a watch channel // A ptr is unsafely created from the raw ptr in httpsend once the // user's code has completed and sends the new HandlerMemory so we // can resume execution of this HTTP request let (tx, rx): (Sender>, Receiver>) = oneshot::channel(); let tx_ptr = Box::into_raw(Box::new(tx)) as i64; - event.push_fixed(0, tx_ptr); + event.push_fixed(0, tx_ptr)?; let event_emit = EventEmit { id: i64::from(BuiltInEvents::HTTPCONN), payload: Some(event), }; - let event_tx = EVENT_TX.get().unwrap(); + let event_tx = EVENT_TX.get().ok_or(VMError::ShutDown)?; let mut err_res = Response::new("Error synchronizing `send` for HTTP request".into()); *err_res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; if event_tx.send(event_emit).is_err() { @@ -3031,740 +3053,756 @@ pub static OPCODES: Lazy> = Lazy::new(|| { } }; // Get the status from the user response and begin building the response object - let status = response_hm.read_fixed(0) as u16; - let mut res = Response::builder().status(StatusCode::from_u16(status).unwrap()); + let status = response_hm.read_fixed(0)? as u16; + let mut res = Response::builder() + .status(StatusCode::from_u16(status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)); // Get the headers and populate the response object + // TODO: figure out how to handle this potential panic let headers = res.headers_mut().unwrap(); - let header_hms = response_hm.read_fractal(1); + let header_hms = response_hm.read_fractal(1)?; for i in 0..header_hms.len() { let (h, _) = response_hm.read_from_fractal(&header_hms.clone(), i); let (key_hm, _) = response_hm.read_from_fractal(&h, 0); let (val_hm, _) = response_hm.read_from_fractal(&h, 1); - let key = HandlerMemory::fractal_to_string(key_hm); - let val = HandlerMemory::fractal_to_string(val_hm); + let key = HandlerMemory::fractal_to_string(key_hm)?; + let val = HandlerMemory::fractal_to_string(val_hm)?; + // TODO: figure out how to handle this potential panic let name = HeaderName::from_bytes(key.as_bytes()).unwrap(); + // TODO: figure out how to handle this potential panic let value = HeaderValue::from_str(&val).unwrap(); headers.insert(name, value); } // Get the body, populate the response object, and fire it out - let body = HandlerMemory::fractal_to_string(response_hm.read_fractal(2)); + let body = HandlerMemory::fractal_to_string(response_hm.read_fractal(2)?)?; + // TODO: figure out how to handle this potential panic Ok(res.body(body.into()).unwrap()) } io!(httplsn => fn(_args, hand_mem) { Box::pin(async move { - make_server!(&Program::global().http_config, http_listener); - return hand_mem; + // this extra fn is so that we can just use `?` inside of http_listener instead of + // having a bunch of `match`es that call a closure + async fn listen(req: Request) -> Result, Infallible> { + match http_listener(req).await { + Ok(res) => Ok(res), + Err(_) => { + // TODO: log the error? + Ok(Response::builder().status(500).body(Body::empty()).unwrap()) + } + } + } + make_server!(&Program::global().http_config, listen); + return Ok(hand_mem); }) }); cpu!(httpsend => fn(args, hand_mem) { - hand_mem.dupe(args[0], args[0]); // Make sure there's no pointers involved - let mut hm = HandlerMemory::new(None, 1); - HandlerMemory::transfer(&hand_mem, args[0], &mut hm, CLOSURE_ARG_MEM_START); - let res_out = hm.read_fractal(CLOSURE_ARG_MEM_START); + hand_mem.dupe(args[0], args[0])?; // Make sure there's no pointers involved + let mut hm = HandlerMemory::new(None, 1)?; + HandlerMemory::transfer(&hand_mem, args[0], &mut hm, CLOSURE_ARG_MEM_START)?; + let res_out = hm.read_fractal(CLOSURE_ARG_MEM_START)?; for i in 0..res_out.len() { - hm.register_from_fractal(i as i64, &res_out, i); + hm.register_from_fractal(i as i64, &res_out, i)?; } // Get the oneshot channel tx from the raw ptr previously generated in http_listener - let fractal = hand_mem.read_fractal(args[0]); - let tx_ptr = NonNull::new(fractal.read_fixed(3) as *mut Sender>); + let fractal = hand_mem.read_fractal(args[0])?; + let tx_ptr = NonNull::new(fractal.read_fixed(3)? as *mut Sender>); if let Some(tx_nonnull) = tx_ptr { let tx = unsafe { Box::from_raw(tx_nonnull.as_ptr()) }; let (status, string) = match tx.send(hm) { Ok(_) => (1, "ok"), Err(_) => (0, "could not send response to server"), }; - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], status); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(string)); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], status)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(string))?; } else { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 0); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 0)?; hand_mem.push_fractal( args[2], HandlerMemory::str_to_fractal("cannot call send twice for the same connection") - ); + )?; } - None + Ok(None) }); // Datastore opcodes io!(dssetf => fn(args, hand_mem) { Box::pin(async move { - let val = hand_mem.read_fixed(args[2]); - let mut hm = HandlerMemory::new(None, 1); - hm.write_fixed(0, val); - let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let val = hand_mem.read_fixed(args[2])?; + let mut hm = HandlerMemory::new(None, 1)?; + hm.write_fixed(0, val)?; + let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let nskey = format!("{}:{}", ns, key); let ds = Arc::clone(&DS); ds.insert(nskey, hm); - hand_mem + Ok(hand_mem) }) }); io!(dssetv => fn(args, hand_mem) { Box::pin(async move { - let mut hm = HandlerMemory::new(None, 1); - HandlerMemory::transfer(&hand_mem, args[2], &mut hm, 0); - let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let mut hm = HandlerMemory::new(None, 1)?; + HandlerMemory::transfer(&hand_mem, args[2], &mut hm, 0)?; + let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let nskey = format!("{}:{}", ns, key); let ds = Arc::clone(&DS); ds.insert(nskey, hm); - hand_mem + Ok(hand_mem) }) }); io!(dshas => fn(args, mut hand_mem) { Box::pin(async move { - let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let nskey = format!("{}:{}", ns, key); let ds = Arc::clone(&DS); let has = ds.contains_key(&nskey); - hand_mem.write_fixed(args[2], if has { 1i64 } else { 0i64 }); - hand_mem + hand_mem.write_fixed(args[2], if has { 1i64 } else { 0i64 })?; + Ok(hand_mem) }) }); io!(dsdel => fn(args, mut hand_mem) { Box::pin(async move { - let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let nskey = format!("{}:{}", ns, key); let ds = Arc::clone(&DS); let removed = ds.remove(&nskey).is_some(); - hand_mem.write_fixed(args[2], if removed { 1i64 } else { 0i64 }); - hand_mem + hand_mem.write_fixed(args[2], if removed { 1i64 } else { 0i64 })?; + Ok(hand_mem) }) }); io!(dsgetf => fn(args, mut hand_mem) { Box::pin(async move { - let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let nskey = format!("{}:{}", ns, key); let ds = Arc::clone(&DS); let maybe_hm = ds.get(&nskey); - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], if maybe_hm.is_some() { 1i64 } else { 0i64 }); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], if maybe_hm.is_some() { 1i64 } else { 0i64 })?; match maybe_hm { - Some(hm) => hand_mem.push_fixed(args[2], hm.read_fixed(0)), + Some(hm) => hand_mem.push_fixed(args[2], hm.read_fixed(0)?), None => hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("namespace-key pair not found")), - } - hand_mem + }?; + Ok(hand_mem) }) }); io!(dsgetv => fn(args, mut hand_mem) { Box::pin(async move { - let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); - let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])); + let ns = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; + let key = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?; let nskey = format!("{}:{}", ns, key); let ds = Arc::clone(&DS); let maybe_hm = ds.get(&nskey); - hand_mem.init_fractal(args[2]); + hand_mem.init_fractal(args[2])?; match maybe_hm { Some(hm) => { - hand_mem.push_fixed(args[2], 1i64); - HandlerMemory::transfer(&hm, 0, &mut hand_mem, CLOSURE_ARG_MEM_START); - hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START); + hand_mem.push_fixed(args[2], 1i64)?; + HandlerMemory::transfer(&hm, 0, &mut hand_mem, CLOSURE_ARG_MEM_START)?; + hand_mem.push_register(args[2], CLOSURE_ARG_MEM_START)?; }, None => { - hand_mem.push_fixed(args[2], 0i64); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("namespace-key pair not found")) + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("namespace-key pair not found"))?; }, } - hand_mem + Ok(hand_mem) }) }); // seq opcodes cpu!(newseq => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 0i64); - hand_mem.push_fixed(args[2], hand_mem.read_fixed(args[0])); - None + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.push_fixed(args[2], hand_mem.read_fixed(args[0])?)?; + Ok(None) }); cpu!(seqnext => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - let mut seq = hand_mem.read_fractal(args[0]); - let current = seq.read_fixed(0); - let limit = seq.read_fixed(1); + hand_mem.init_fractal(args[2])?; + let mut seq = hand_mem.read_fractal(args[0])?; + let current = seq.read_fixed(0)?; + let limit = seq.read_fixed(1)?; if current < limit { - hand_mem.write_fixed_in_fractal(&mut seq, 0, current + 1); - hand_mem.push_fixed(args[2], 1i64); - hand_mem.push_fixed(args[2], current); + hand_mem.write_fixed_in_fractal(&mut seq, 0, current + 1)?; + hand_mem.push_fixed(args[2], 1i64)?; + hand_mem.push_fixed(args[2], current)?; } else { - hand_mem.push_fixed(args[2], 0i64); + hand_mem.push_fixed(args[2], 0i64)?; let err_msg = "error: sequence out-of-bounds"; - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&err_msg)); + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal(&err_msg))?; } - None + Ok(None) }); unpred_cpu!(seqeach => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { // same as `each` - return hand_mem; + return Ok(hand_mem); } - let mut seq = hand_mem.read_fractal(args[0]); - let current = seq.read_fixed(0); - let limit = seq.read_fixed(1); + let mut seq = hand_mem.read_fractal(args[0])?; + let current = seq.read_fixed(0)?; + let limit = seq.read_fixed(1)?; let subhandler = HandlerFragment::new(args[1], 0); if current >= limit { - return hand_mem; + return Ok(hand_mem); } - hand_mem.write_fixed_in_fractal(&mut seq, 0, limit); + hand_mem.write_fixed_in_fractal(&mut seq, 0, limit)?; // array of potentially many levels of nested fractals for i in current..limit { // array element is $1 argument of the closure memory space - hand_mem.write_fixed(CLOSURE_ARG_MEM_START + 1, i); - hand_mem = subhandler.clone().run(hand_mem).await; + hand_mem.write_fixed(CLOSURE_ARG_MEM_START + 1, i)?; + hand_mem = subhandler.clone().run(hand_mem).await?; } - hand_mem + Ok(hand_mem) }) }); unpred_cpu!(seqwhile => fn(args, mut hand_mem) { Box::pin(async move { if args[1] == NOP_ID { - panic!("NOP closure provided instead of a while condition"); + return Err(VMError::InvalidNOP); } - let seq = hand_mem.read_fractal(args[0]); - let mut current = seq.read_fixed(0); - let limit = seq.read_fixed(1); + let seq = hand_mem.read_fractal(args[0])?; + let mut current = seq.read_fixed(0)?; + let limit = seq.read_fixed(1)?; drop(seq); let cond_handler = HandlerFragment::new(args[1], 0); let body_handler = HandlerFragment::new(args[2], 0); if current >= limit { - return hand_mem; + return Ok(hand_mem); } - hand_mem = cond_handler.clone().run(hand_mem).await; - while current < limit && hand_mem.read_fixed(CLOSURE_ARG_MEM_START) > 0 { + hand_mem = cond_handler.clone().run(hand_mem).await?; + while current < limit && hand_mem.read_fixed(CLOSURE_ARG_MEM_START)? > 0 { if args[2] != NOP_ID { - hand_mem = body_handler.clone().run(hand_mem).await; + hand_mem = body_handler.clone().run(hand_mem).await?; } current = current + 1; - hand_mem = cond_handler.clone().run(hand_mem).await; + hand_mem = cond_handler.clone().run(hand_mem).await?; } - let mut seq = hand_mem.read_fractal(args[0]); - hand_mem.write_fixed_in_fractal(&mut seq, 0, current); - hand_mem + let mut seq = hand_mem.read_fractal(args[0])?; + hand_mem.write_fixed_in_fractal(&mut seq, 0, current)?; + Ok(hand_mem) }) }); unpred_cpu!(seqdo => fn(args, mut hand_mem) { Box::pin(async move { - let seq = hand_mem.read_fractal(args[0]); - let mut current = seq.read_fixed(0); - let limit = seq.read_fixed(1); + let seq = hand_mem.read_fractal(args[0])?; + let mut current = seq.read_fixed(0)?; + let limit = seq.read_fixed(1)?; drop(seq); let subhandler = HandlerFragment::new(args[1], 0); loop { if args[1] != NOP_ID { - hand_mem = subhandler.clone().run(hand_mem).await; + hand_mem = subhandler.clone().run(hand_mem).await?; } current = current + 1; - if current >= limit || hand_mem.read_fixed(CLOSURE_ARG_MEM_START) == 0 { + if current >= limit || hand_mem.read_fixed(CLOSURE_ARG_MEM_START)? == 0 { break; } } - let mut seq = hand_mem.read_fractal(args[0]); - hand_mem.write_fixed_in_fractal(&mut seq, 0, current); - hand_mem + let mut seq = hand_mem.read_fractal(args[0])?; + hand_mem.write_fixed_in_fractal(&mut seq, 0, current)?; + Ok(hand_mem) }) }); unpred_cpu!(selfrec => fn(args, mut hand_mem) { Box::pin(async move { - let mut hm = HandlerMemory::fork(hand_mem.clone()); + let mut hm = HandlerMemory::fork(hand_mem.clone())?; // MUST read these first in case the arguments are themselves closure args being overwritten // for the recursive function. // Since we mutate the `Self` object in this, it *must* be read as mutable *first* to make // sure that the later registration of the `Self` object is pointing at the correct copy - let slf = hm.read_mut_fractal(args[0]); + let slf = hm.read_mut_fractal(args[0])?; let recurse_fn = HandlerFragment::new(slf[1].1, 0); let seq_addr = slf[0].0; drop(slf); - hm.register(CLOSURE_ARG_MEM_START + 1, args[0], false); - hm.register(CLOSURE_ARG_MEM_START + 2, args[1], false); - let seq = hm.read_mut_fractal_by_idx(seq_addr); + hm.register(CLOSURE_ARG_MEM_START + 1, args[0], false)?; + hm.register(CLOSURE_ARG_MEM_START + 2, args[1], false)?; + let seq = hm.read_mut_fractal_by_idx(seq_addr)?; let curr = seq[0].1; if curr < seq[1].1 { seq[0].1 = curr + 1; - hm = recurse_fn.run(hm).await; - hm = hm.drop_parent(); + hm = recurse_fn.run(hm).await?; + hm = hm.drop_parent()?; // CANNOT `join` the memory like usual because the nested `recurse` calls have set "future" // values in the handler and will cause weird behavior. Only transfer the Self mutation and // the return value between iterations - HandlerMemory::transfer(&mut hm, CLOSURE_ARG_MEM_START, &mut hand_mem, args[2]); - HandlerMemory::transfer(&mut hm, CLOSURE_ARG_MEM_START + 1, &mut hand_mem, args[0]); + HandlerMemory::transfer(&mut hm, CLOSURE_ARG_MEM_START, &mut hand_mem, args[2])?; + HandlerMemory::transfer(&mut hm, CLOSURE_ARG_MEM_START + 1, &mut hand_mem, args[0])?; } else { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("error: sequence out-of-bounds")); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("error: sequence out-of-bounds"))?; } - hand_mem + Ok(hand_mem) }) }); cpu!(seqrec => fn(args, hand_mem) { if args[1] == NOP_ID { - panic!("NOP can't be recursive"); + return Err(VMError::InvalidNOP); } - hand_mem.init_fractal(args[2]); - hand_mem.push_register(args[2], args[0]); - hand_mem.push_fixed(args[2], args[1]); - None + hand_mem.init_fractal(args[2])?; + hand_mem.push_register(args[2], args[0])?; + hand_mem.push_fixed(args[2], args[1])?; + Ok(None) }); // "Special" opcodes cpu!(exitop => fn(args, hand_mem) { - io::stdout().flush().unwrap(); - io::stderr().flush().unwrap(); - std::process::exit(hand_mem.read_fixed(args[0]) as i32); + io::stdout().flush().map_err(VMError::IOError)?; + io::stderr().flush().map_err(VMError::IOError)?; + std::process::exit(hand_mem.read_fixed(args[0])? as i32); }); cpu!(stdoutp => fn(args, hand_mem) { - let out_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let out_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; print!("{}", out_str); - None + Ok(None) }); cpu!(stderrp => fn(args, hand_mem) { - let err_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])); + let err_str = HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[0])?)?; eprint!("{}", err_str); - None + Ok(None) }); // set opcodes use args[0] directly, since the relevant value directly // fits in i64, and write it to args[2] cpu!(seti64 => fn(args, hand_mem) { let data = args[0]; - hand_mem.write_fixed(args[2], data); - None + hand_mem.write_fixed(args[2], data)?; + Ok(None) }); cpu!(seti32 => fn(args, hand_mem) { let data = (args[0] as i32) as i64; - hand_mem.write_fixed(args[2], data); - None + hand_mem.write_fixed(args[2], data)?; + Ok(None) }); cpu!(seti16 => fn(args, hand_mem) { let data = (args[0] as i16) as i64; - hand_mem.write_fixed(args[2], data); - None + hand_mem.write_fixed(args[2], data)?; + Ok(None) }); cpu!(seti8 => fn(args, hand_mem) { let data = (args[0] as i8) as i64; - hand_mem.write_fixed(args[2], data); - None + hand_mem.write_fixed(args[2], data)?; + Ok(None) }); cpu!(setf64 => fn(args, hand_mem) { let data = i64::from_ne_bytes((args[0] as f64).to_ne_bytes()); - hand_mem.write_fixed(args[2], data); - None + hand_mem.write_fixed(args[2], data)?; + Ok(None) }); cpu!(setf32 => fn(args, hand_mem) { let data = i32::from_ne_bytes((args[0] as f32).to_ne_bytes()) as i64; - hand_mem.write_fixed(args[2], data); - None + hand_mem.write_fixed(args[2], data)?; + Ok(None) }); cpu!(setbool => fn(args, hand_mem) { let data = if args[0] == 0 { 0i64 } else { 1i64 }; - hand_mem.write_fixed(args[2], data); - None + hand_mem.write_fixed(args[2], data)?; + Ok(None) }); cpu!(setestr => fn(args, hand_mem) { let empty_str = FractalMemory::new(vec![(0, 0)]); - hand_mem.write_fractal(args[2], &empty_str); - None + hand_mem.write_fractal(args[2], &empty_str)?; + Ok(None) }); // copy opcodes used for let variable reassignments cpu!(copyi8 => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copyi16 => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copyi32 => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copyi64 => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copyvoid => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copyf32 => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copyf64 => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copybool => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); - hand_mem.write_fixed(args[2], val); - None + let val = hand_mem.read_fixed(args[0])?; + hand_mem.write_fixed(args[2], val)?; + Ok(None) }); cpu!(copystr => fn(args, hand_mem) { - let pascal_string = hand_mem.read_fractal(args[0]); - hand_mem.write_fractal(args[2], &pascal_string); - None + let pascal_string = hand_mem.read_fractal(args[0])?; + hand_mem.write_fractal(args[2], &pascal_string)?; + Ok(None) }); cpu!(copyarr => fn(args, hand_mem) { // args = [in_addr, unused, out_addr] - hand_mem.dupe(args[0], args[2]); - None + hand_mem.dupe(args[0], args[2])?; + Ok(None) }); cpu!(zeroed => fn(args, hand_mem) { - hand_mem.write_fixed(args[2], 0); - None + hand_mem.write_fixed(args[2], 0)?; + Ok(None) }); // Trig opcodes cpu!(lnf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.ln().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(logf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.log10().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(sinf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.sin().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(cosf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.cos().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(tanf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.tan().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(asinf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.asin().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(acosf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.acos().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(atanf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.atan().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(sinhf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.sinh().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(coshf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.cosh().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(tanhf64 => fn(args, hand_mem) { - let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0]).to_ne_bytes()); + let a = f64::from_ne_bytes(hand_mem.read_fixed(args[0])?.to_ne_bytes()); let out = i64::from_ne_bytes(a.tanh().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); // Error, Maybe, Result, Either opcodes cpu!(error => fn(args, hand_mem) { - hand_mem.register(args[2], args[0], true); - None + hand_mem.register(args[2], args[0], true)?; + Ok(None) }); cpu!(refv => fn(args, hand_mem) { - hand_mem.register(args[2], args[0], true); - None + hand_mem.register(args[2], args[0], true)?; + Ok(None) }); cpu!(reff => fn(args, hand_mem) { - hand_mem.register(args[2], args[0], false); - None + hand_mem.register(args[2], args[0], false)?; + Ok(None) }); cpu!(noerr => fn(args, hand_mem) { let empty_string = FractalMemory::new(vec![(0, 0)]); - hand_mem.write_fractal(args[2], &empty_string); - None + hand_mem.write_fractal(args[2], &empty_string)?; + Ok(None) }); cpu!(errorstr => fn(args, hand_mem) { - hand_mem.register(args[2], args[0], true); - None + hand_mem.register(args[2], args[0], true)?; + Ok(None) }); cpu!(someM => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 1i64); - let val_size = hand_mem.read_fixed(args[1]); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 1i64)?; + let val_size = hand_mem.read_fixed(args[1])?; if val_size == 0 { - hand_mem.push_register(args[2], args[0]); + hand_mem.push_register(args[2], args[0])?; } else { - let val = hand_mem.read_fixed(args[0]); - hand_mem.push_fixed(args[2], val); + let val = hand_mem.read_fixed(args[0])?; + hand_mem.push_fixed(args[2], val)?; } - None + Ok(None) }); cpu!(noneM => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 0i64); - None + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 0i64)?; + Ok(None) }); cpu!(isSome => fn(args, hand_mem) { - hand_mem.register_out(args[0], 0, args[2]); - None + hand_mem.register_out(args[0], 0, args[2])?; + Ok(None) }); cpu!(isNone => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); - hand_mem.write_fixed(args[2], if val == 0i64 { 1i64 } else { 0i64 }); - None + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; + hand_mem.write_fixed(args[2], if val == 0i64 { 1i64 } else { 0i64 })?; + Ok(None) }); cpu!(getOrM => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; if val == 1i64 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; } else { if args[1] < 0 { - let val = hand_mem.read_fixed(args[1]); - hand_mem.write_fixed(args[2], val); + let val = hand_mem.read_fixed(args[1])?; + hand_mem.write_fixed(args[2], val)?; } else { - let (data, is_fractal) = hand_mem.read_either(args[1]); + let (data, is_fractal) = hand_mem.read_either(args[1])?; if is_fractal { - hand_mem.register(args[2], args[1], true); + hand_mem.register(args[2], args[1], true)?; } else { - hand_mem.write_fixed(args[2], data.read_fixed(0)); + hand_mem.write_fixed(args[2], data.read_fixed(0)?)?; } } } - None + Ok(None) }); cpu!(getMaybe => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let variant = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let variant = fractal.read_fixed(0)?; if variant == 1 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; + Ok(None) } else { - panic!("runtime error: illegal access"); + Err(VMError::IllegalAccess) } - None }); cpu!(okR => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 1i64); - let val_size = hand_mem.read_fixed(args[1]); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 1i64)?; + let val_size = hand_mem.read_fixed(args[1])?; if val_size == 0 { - hand_mem.push_register(args[2], args[0]); + hand_mem.push_register(args[2], args[0])?; } else { - let val = hand_mem.read_fixed(args[0]); - hand_mem.push_fixed(args[2], val); + let val = hand_mem.read_fixed(args[0])?; + hand_mem.push_fixed(args[2], val)?; } - None + Ok(None) }); cpu!(err => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 0i64); - hand_mem.push_register(args[2], args[0]); - None + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 0i64)?; + hand_mem.push_register(args[2], args[0])?; + Ok(None) }); cpu!(isOk => fn(args, hand_mem) { - hand_mem.register_out(args[0], 0, args[2]); - None + hand_mem.register_out(args[0], 0, args[2])?; + Ok(None) }); cpu!(isErr => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); - hand_mem.write_fixed(args[2], if val == 0i64 { 1i64 } else { 0i64 }); - None + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; + hand_mem.write_fixed(args[2], if val == 0i64 { 1i64 } else { 0i64 })?; + Ok(None) }); cpu!(getOrR => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; if val == 1i64 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; } else { - let (data, is_fractal) = hand_mem.read_either(args[1]); + let (data, is_fractal) = hand_mem.read_either(args[1])?; if is_fractal { - hand_mem.register(args[2], args[1], true); + hand_mem.register(args[2], args[1], true)?; } else { - hand_mem.write_fixed(args[2], data.read_fixed(0)); + hand_mem.write_fixed(args[2], data.read_fixed(0)?)?; } } - None + Ok(None) }); cpu!(getOrRS => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; if val == 1i64 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; } else { - let f = HandlerMemory::str_to_fractal(&HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1]))); - hand_mem.write_fractal(args[2], &f); + let f = HandlerMemory::str_to_fractal(&HandlerMemory::fractal_to_string(hand_mem.read_fractal(args[1])?)?); + hand_mem.write_fractal(args[2], &f)?; } - None + Ok(None) }); cpu!(getR => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; if val == 1i64 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; + Ok(None) } else { - panic!("runtime error: illegal access"); + Err(VMError::IllegalAccess) } - None }); cpu!(getErr => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; if val == 0i64 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; } else { - let (data, is_fractal) = hand_mem.read_either(args[1]); + let (data, is_fractal) = hand_mem.read_either(args[1])?; if is_fractal { - hand_mem.register(args[2], args[1], true); + hand_mem.register(args[2], args[1], true)?; } else { - hand_mem.write_fixed(args[2], data.read_fixed(0)); + hand_mem.write_fixed(args[2], data.read_fixed(0)?)?; } } - None + Ok(None) }); cpu!(resfrom => fn(args, hand_mem) { // args = [arr_addr, arr_idx_addr, outer_addr] // a guarded copy of data from an array to a result object - hand_mem.init_fractal(args[2]); - let fractal = hand_mem.read_fractal(args[1]); - let val = fractal.read_fixed(0); + hand_mem.init_fractal(args[2])?; + let fractal = hand_mem.read_fractal(args[1])?; + let val = fractal.read_fixed(0)?; if val == 0 { - hand_mem.write_fractal(args[2], &fractal); - return None; + hand_mem.write_fractal(args[2], &fractal)?; + return Ok(None); } - let inner_addr = fractal.read_fixed(1) as usize; - let arr = hand_mem.read_fractal(args[0]); + let inner_addr = fractal.read_fixed(1)? as usize; + let arr = hand_mem.read_fractal(args[0])?; if arr.len() > inner_addr { - hand_mem.push_fixed(args[2], 1); - hand_mem.push_register_out(args[2], &arr, inner_addr); + hand_mem.push_fixed(args[2], 1)?; + hand_mem.push_register_out(args[2], &arr, inner_addr)?; } else { - hand_mem.push_fixed(args[2], 0); - hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("out-of-bounds access")); + hand_mem.push_fixed(args[2], 0)?; + hand_mem.push_fractal(args[2], HandlerMemory::str_to_fractal("out-of-bounds access"))?; } - None + Ok(None) }); cpu!(mainE => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 1i64); - let val_size = hand_mem.read_fixed(args[1]); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 1i64)?; + let val_size = hand_mem.read_fixed(args[1])?; if val_size == 0 { - hand_mem.push_register(args[2], args[0]); + hand_mem.push_register(args[2], args[0])?; } else { - let val = hand_mem.read_fixed(args[0]); - hand_mem.push_fixed(args[2], val); + let val = hand_mem.read_fixed(args[0])?; + hand_mem.push_fixed(args[2], val)?; } - None + Ok(None) }); cpu!(altE => fn(args, hand_mem) { - hand_mem.init_fractal(args[2]); - hand_mem.push_fixed(args[2], 0i64); - let val_size = hand_mem.read_fixed(args[1]); + hand_mem.init_fractal(args[2])?; + hand_mem.push_fixed(args[2], 0i64)?; + let val_size = hand_mem.read_fixed(args[1])?; if val_size == 0 { - hand_mem.push_register(args[2], args[0]); + hand_mem.push_register(args[2], args[0])?; } else { - let val = hand_mem.read_fixed(args[0]); - hand_mem.push_fixed(args[2], val); + let val = hand_mem.read_fixed(args[0])?; + hand_mem.push_fixed(args[2], val)?; } - None + Ok(None) }); cpu!(isMain => fn(args, hand_mem) { - hand_mem.register_out(args[0], 0, args[2]); - None + hand_mem.register_out(args[0], 0, args[2])?; + Ok(None) }); cpu!(isAlt => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); - hand_mem.write_fixed(args[2], if val == 0i64 { 1i64 } else { 0i64 }); - None + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; + hand_mem.write_fixed(args[2], if val == 0i64 { 1i64 } else { 0i64 })?; + Ok(None) }); cpu!(mainOr => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; if val == 1i64 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; } else { - let (data, is_fractal) = hand_mem.read_either(args[1]); + let (data, is_fractal) = hand_mem.read_either(args[1])?; if is_fractal { - hand_mem.register(args[2], args[1], true); + hand_mem.register(args[2], args[1], true)?; } else { - hand_mem.write_fixed(args[2], data.read_fixed(0)); + hand_mem.write_fixed(args[2], data.read_fixed(0)?)?; } } - None + Ok(None) }); cpu!(altOr => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let val = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let val = fractal.read_fixed(0)?; if val == 0i64 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; } else { - let (data, is_fractal) = hand_mem.read_either(args[1]); + let (data, is_fractal) = hand_mem.read_either(args[1])?; if is_fractal { - hand_mem.register(args[2], args[1], true); + hand_mem.register(args[2], args[1], true)?; } else { - hand_mem.write_fixed(args[2], data.read_fixed(0)); + hand_mem.write_fixed(args[2], data.read_fixed(0)?)?; } } - None + Ok(None) }); cpu!(getMain => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let variant = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let variant = fractal.read_fixed(0)?; if variant == 1 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; + Ok(None) } else { - panic!("runtime error: illegal access"); + Err(VMError::IllegalAccess) } - None }); cpu!(getAlt => fn(args, hand_mem) { - let fractal = hand_mem.read_fractal(args[0]); - let variant = fractal.read_fixed(0); + let fractal = hand_mem.read_fractal(args[0])?; + let variant = fractal.read_fixed(0)?; if variant == 0 { - hand_mem.register_out(args[0], 1, args[2]); + hand_mem.register_out(args[0], 1, args[2])?; + Ok(None) } else { - panic!("runtime error: illegal access"); + Err(VMError::IllegalAccess) } - None }); cpu!(hashf => fn(args, hand_mem) { - let val = hand_mem.read_fixed(args[0]); + let val = hand_mem.read_fixed(args[0])?; let mut hasher = XxHash64::with_seed(0xfa57); hasher.write_i64(val); let out = i64::from_ne_bytes(hasher.finish().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); cpu!(hashv => fn(args, hand_mem) { @@ -3772,38 +3810,38 @@ pub static OPCODES: Lazy> = Lazy::new(|| { let addr = args[0]; if addr < 0 { // It's a string! - let pascal_string = hand_mem.read_fractal(args[0]); - let strlen = pascal_string.read_fixed(0) as f64; + let pascal_string = hand_mem.read_fractal(args[0])?; + let strlen = pascal_string.read_fixed(0)? as f64; let intlen = 1 + (strlen / 8.0).ceil() as usize; for i in 0..intlen { - hasher.write_i64(pascal_string.read_fixed(i)); + hasher.write_i64(pascal_string.read_fixed(i)?); } } else { - let mut stack: Vec = vec![hand_mem.read_fractal(args[0])]; + let mut stack: Vec = vec![hand_mem.read_fractal(args[0])?]; while stack.len() > 0 { - let fractal = stack.pop().unwrap(); + let fractal = stack.pop().ok_or(VMError::IllegalAccess)?; for i in 0..fractal.len() { let (data, is_fractal) = hand_mem.read_from_fractal(&fractal, i); if is_fractal { stack.push(data); } else { - hasher.write_i64(data.read_fixed(0)); + hasher.write_i64(data.read_fixed(0)?); } } } } let out = i64::from_ne_bytes(hasher.finish().to_ne_bytes()); - hand_mem.write_fixed(args[2], out); - None + hand_mem.write_fixed(args[2], out)?; + Ok(None) }); // king opcode cpu!(emit => fn(args, hand_mem) { let event = EventEmit { id: args[0], - payload: HandlerMemory::alloc_payload(args[0], args[1], &hand_mem), + payload: HandlerMemory::alloc_payload(args[0], args[1], &hand_mem)?, }; - Some(event) + Ok(Some(event)) }); o @@ -3813,11 +3851,11 @@ impl From for &ByteOpcode { fn from(v: i64) -> Self { let opc = OPCODES.get(&v); if opc.is_none() { - panic!(format!( + panic!( "Illegal byte opcode {} ({})", v, str::from_utf8(&v.to_ne_bytes()).unwrap() - )); + ); } return &opc.unwrap(); } diff --git a/avm/src/vm/program.rs b/avm/src/vm/program.rs index 21277ab11..fbed8bcc9 100644 --- a/avm/src/vm/program.rs +++ b/avm/src/vm/program.rs @@ -51,7 +51,7 @@ impl From for GraphOpcode { } else if v == custom_num { return GraphOpcode::CUSTOMEVENT; } else { - panic!(format!("Illegal graph opcode {}", v)); + panic!("Illegal graph opcode {}", v); } } } diff --git a/avm/src/vm/run.rs b/avm/src/vm/run.rs index 2d42369bf..9cfec8466 100644 --- a/avm/src/vm/run.rs +++ b/avm/src/vm/run.rs @@ -1,9 +1,11 @@ +use std::convert::TryInto; use std::fs::File; use std::io::Read; use std::path::Path; use std::sync::Arc; -use byteorder::{LittleEndian, ReadBytesExt}; +use byteorder::ByteOrder; +use byteorder::LittleEndian; use flate2::read::GzDecoder; use once_cell::sync::OnceCell; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; @@ -12,6 +14,7 @@ use crate::vm::event::{BuiltInEvents, EventEmit, HandlerFragment}; use crate::vm::http::{HttpConfig, HttpType}; use crate::vm::memory::HandlerMemory; use crate::vm::program::{Program, PROGRAM}; +use crate::vm::{VMError, VMResult}; pub static EVENT_TX: OnceCell> = OnceCell::new(); @@ -22,30 +25,31 @@ pub struct VM { } impl VM { - pub fn new() -> VM { + pub fn new() -> VMResult { let (event_tx, event_rx) = unbounded_channel(); // Hackery relying on VM being a singleton :( TODO: Refactor such that event_tx is accessible // outside of the opcodes and instruction scheduler for http and future IO sources - EVENT_TX.set(event_tx.clone()).unwrap(); - return VM { event_tx, event_rx }; + EVENT_TX + .set(event_tx.clone()) + .map_err(|_| VMError::AlreadyRunning)?; + return Ok(VM { event_tx, event_rx }); } - pub fn add(self: &mut VM, event: EventEmit) { - let event_sent = self.event_tx.send(event); - if event_sent.is_err() { - eprintln!("Event transmission error"); - std::process::exit(1); - } + pub fn add(self: &mut VM, event: EventEmit) -> VMResult<()> { + self.event_tx.send(event).map_err(|_| VMError::ShutDown) } - fn sched_event(self: &mut VM, event: EventEmit) { - // skip NOP event always + fn sched_event(self: &mut VM, event: EventEmit) -> VMResult<()> { + // skip NOP event always, but it's not an error to receive it. if event.id == i64::from(BuiltInEvents::NOP) { - return; + return Ok(()); } // schedule 1st fragment of each handler of this event - let handlers = Program::global().event_handlers.get(&event.id).unwrap(); + let handlers = Program::global() + .event_handlers + .get(&event.id) + .ok_or(VMError::EventNotDefined(event.id))?; for (i, hand) in handlers.iter().enumerate() { // first fragment of this handler let frag = HandlerFragment::new(event.id, i); @@ -54,60 +58,69 @@ impl VM { None => None, }; // memory frag representing the memory for each handler call - let hand_mem = HandlerMemory::new(payload, hand.mem_req); + let hand_mem = HandlerMemory::new(payload, hand.mem_req)?; frag.spawn(hand_mem); } + Ok(()) } // run the vm backed by an event loop - pub async fn run(self: &mut VM) { - loop { - let event = self.event_rx.recv().await; - self.sched_event(event.unwrap()); + pub async fn run(self: &mut VM) -> VMResult<()> { + while let Some(event) = self.event_rx.recv().await { + self.sched_event(event)?; } + Ok(()) } } -pub async fn run_file(fp: &str, delete_after_load: bool) { - let fptr = File::open(fp); - if fptr.is_err() { - eprintln!("File not found: {}", fp); - std::process::exit(2); - } +pub async fn run_file(fp: &str, delete_after_load: bool) -> VMResult<()> { + let filepath = Path::new(fp); + let mut file = File::open(filepath).map_err(|_| VMError::FileNotFound(fp.to_string()))?; + let metadata = file.metadata().map_err(|_| { + VMError::InvalidFile(format!( + "Unable to get file metadata for file at {}. Are you sure it's a file?", + fp + )) + })?; + let fsize = metadata + .len() + .try_into() + .map_err(|_| VMError::InvalidFile(format!("{} is a very big file on a 32-bit system", fp)))?; // Test if it's gzip compressed - let mut bytes = Vec::new(); - File::open(fp).unwrap().read_to_end(&mut bytes).unwrap(); - let gz = GzDecoder::new(bytes.as_slice()); - let mut bytecode; + // TODO: new_uninit is nightly-only right now, we can use it to do this and achieve gains: + // let mut bytes = Box::new_uninit_slice(fsize); + // file.read_exact(&mut bytes).or(...)?; + let mut bytes = Vec::with_capacity(fsize); + file.read_to_end(&mut bytes).map_err(VMError::IOError)?; + let mut gz = GzDecoder::new(bytes.as_slice()); if gz.header().is_some() { - let count = gz.bytes().count(); - bytecode = vec![0; count / 8]; - let mut gz = GzDecoder::new(bytes.as_slice()); - gz.read_i64_into::(&mut bytecode).unwrap(); - } else { - let bytes = File::open(fp).unwrap().bytes().count(); - bytecode = vec![0; bytes / 8]; - let mut f = File::open(fp).unwrap(); - f.read_i64_into::(&mut bytecode).unwrap(); + let mut uncompressed = Vec::with_capacity(fsize * 2); + let _bytes_read = gz + .read_to_end(&mut uncompressed) + .map_err(VMError::IOError)?; + bytes = uncompressed; } + let bytecode = bytes + .as_slice() + .chunks(8) + .map(LittleEndian::read_i64) + .collect::>(); if delete_after_load { - std::fs::remove_file(Path::new(fp)).unwrap(); + std::fs::remove_file(Path::new(fp)).map_err(VMError::IOError)?; } - run(bytecode, HttpType::HTTP(HttpConfig { port: 8000 })).await; + run(bytecode, HttpType::HTTP(HttpConfig { port: 8000 })).await } -pub async fn run(bytecode: Vec, http_config: HttpType) { +pub async fn run(bytecode: Vec, http_config: HttpType) -> VMResult<()> { let program = Program::load(bytecode, http_config); - let set_global = PROGRAM.set(program); - if set_global.is_err() { - eprintln!("Failed to load bytecode"); - std::process::exit(1); - } - let mut vm = VM::new(); - let start = EventEmit { - id: i64::from(BuiltInEvents::START), + PROGRAM + .set(program) + .map_err(|_| VMError::Other("A program is already loaded".to_string()))?; + let mut vm = VM::new()?; + const START: EventEmit = EventEmit { + id: BuiltInEvents::START as i64, payload: None, }; - vm.add(start); - vm.run().await; + vm.add(START)?; + vm.run().await } diff --git a/avm/src/vm/telemetry.rs b/avm/src/vm/telemetry.rs index 1a6bada99..606b030f3 100644 --- a/avm/src/vm/telemetry.rs +++ b/avm/src/vm/telemetry.rs @@ -36,6 +36,6 @@ pub async fn log(event: &str) { .await .is_ok() { - // Do nothing + // do nothing } }