use { crate::object::Object, rhai::{FnNamespace, Module}, std::{cell::RefCell, rc::Rc}, }; mod optypes { use { crate::{ label::UnboundLabel, object::{Object, RelocKey, RelocType, SymbolRef}, }, rhai::{Dynamic, EvalAltResult, ImmutableString, Position}, }; pub type R = u8; pub type B = i8; pub type H = i16; pub type W = i32; pub type D = i64; pub type A = Dynamic; pub type O = Dynamic; pub type P = Dynamic; pub fn insert_reloc( obj: &mut Object, ty: RelocType, val: &Dynamic, ) -> Result<(), EvalAltResult> { match () { _ if val.is::() => { obj.relocation(RelocKey::Symbol(val.clone_cast::().0), ty) } _ if val.is::() => { obj.relocation(RelocKey::Symbol(val.clone_cast::().0), ty) } _ if val.is::() => { obj.relocation(RelocKey::Symbol(val.clone_cast::().symbol.0), ty) } _ if val.is_string() => { obj.relocation(RelocKey::Label(val.clone_cast::()), ty) } _ if val.is_int() => { let int = val.clone_cast::(); match ty { RelocType::Rel32 => obj.sections.text.extend((int as i32).to_le_bytes()), RelocType::Rel16 => obj.sections.text.extend((int as i16).to_le_bytes()), RelocType::Abs64 => obj.sections.text.extend(int.to_le_bytes()), } } _ => { return Err(EvalAltResult::ErrorMismatchDataType( "SybolRef, UnboundLabel, String or Int".to_owned(), val.type_name().to_owned(), Position::NONE, )) } } Ok(()) } macro_rules! gen_insert { (le_bytes: [$($lety:ident),* $(,)?]) => { macro_rules! insert { $(($thing:expr, $obj: expr, $lety) => { $obj.sections.text.extend($thing.to_le_bytes()); };)* ($thing:expr, $obj:expr, A) => { $crate::ins::optypes::insert_reloc( $obj, $crate::object::RelocType::Abs64, $thing )? }; ($thing:expr, $obj:expr, O) => { $crate::ins::optypes::insert_reloc( $obj, $crate::object::RelocType::Rel32, $thing )? }; ($thing:expr, $obj:expr, P) => { $crate::ins::optypes::insert_reloc( $obj, $crate::object::RelocType::Rel16, $thing )? }; } }; } gen_insert!(le_bytes: [R, B, H, W, D]); #[allow(clippy::single_component_path_imports)] pub(super) use insert; use crate::data::DataRef; } mod rity { pub use super::optypes::{A, O, P, R}; pub type B = i64; pub type H = i64; pub type W = i64; pub type D = i64; } mod generic { use {crate::object::Object, rhai::EvalAltResult}; pub(super) fn convert_op(from: A) -> Result where B: TryFrom, >::Error: std::error::Error + Sync + Send + 'static, { B::try_from(from).map_err(|e| { EvalAltResult::ErrorSystem("Data conversion error".to_owned(), Box::new(e)) }) } macro_rules! gen_ins { ($($($name:ident : $ty:ty),*;)*) => { paste::paste! { $(#[inline] pub fn [<$($ty:lower)*>]( obj: &mut Object, opcode: u8, $($name: $crate::ins::optypes::$ty),*, ) -> Result<(), EvalAltResult> { obj.sections.text.push(opcode); $($crate::ins::optypes::insert!(&$name, obj, $ty);)* Ok(()) })* macro_rules! gen_ins_fn { $(($obj:expr, $opcode:expr, [<$($ty)*>]) => { move |$($name: $crate::ins::rity::$ty),*| { $crate::ins::generic::[<$($ty:lower)*>]( &mut *$obj.borrow_mut(), $opcode, $( $crate::ins::generic::convert_op::< _, $crate::ins::optypes::$ty >($name)? ),* )?; Ok(()) } };)* ($obj:expr, $opcode:expr, N) => { move || { $crate::ins::generic::n(&mut *$obj.borrow_mut(), $opcode); Ok(()) } }; } } }; } #[inline] pub fn n(obj: &mut Object, opcode: u8) { obj.sections.text.push(opcode); } gen_ins! { o0: R, o1: R; o0: R, o1: R, o2: R; o0: R, o1: R, o2: R, o3: R; o0: R, o1: R, o2: B; o0: R, o1: R, o2: H; o0: R, o1: R, o2: W; o0: R, o1: R, o2: D; o0: R, o1: B; o0: R, o1: H; o0: R, o1: W; o0: R, o1: D; o0: R, o1: R, o2: A; o0: R, o1: R, o2: A, o3: H; o0: R, o1: R, o2: O, o3: H; o0: R, o1: R, o2: P, o3: H; o0: R, o1: R, o2: O; o0: R, o1: R, o2: P; o0: O; o0: P; } #[allow(clippy::single_component_path_imports)] pub(super) use gen_ins_fn; } macro_rules! instructions { ( ($module:expr, $obj:expr $(,)?) { $($opcode:expr, $mnemonic:ident, $ops:ident, $doc:literal;)* } ) => {{ let (module, obj) = ($module, $obj); $({ let obj = Rc::clone(&obj); let hash = module.set_native_fn( paste::paste!(stringify!([<$mnemonic:lower>])), generic::gen_ins_fn!( obj, $opcode, $ops ) ); module.update_fn_namespace(hash, FnNamespace::Global); })* }}; } pub fn setup(module: &mut Module, obj: Rc>) { with_builtin_macros::with_builtin! { let $spec = include_from_root!("../hbbytecode/instructions.in") in { instructions!((module, obj) { $spec }); } } }