use crate::errors::lpanic;
#[cfg(feature = "chip8")]
pub mod chip8;
#[cfg(feature = "chip8-raw")]
pub mod chip8_raw;
pub mod outs;
pub type SymbolPosition = usize;
pub type USIWrap = Option<Vec<(RcSym, SymbolPosition)>>;
pub trait SymConv {
fn from_ptr<T: PtrSize>(a: T) -> Self;
fn from_dat<T: DatSize>(a: T) -> Self;
fn into_ptr<T: PtrSize, E: Integral>(&self) -> T;
}
pub trait ArchSym<T: SymConv> {
fn get_uk_sym(&self) -> Option<RcSym>;
fn set_sym(&mut self, a: T) -> ();
}
pub trait ArchMcrInst<T: SymConv> {
fn get_output_bytes(&self) -> Vec<u8>;
fn check_symbols(&self) -> bool;
fn get_symbols(&self) -> USIWrap;
fn get_length(&self) -> SymbolPosition;
fn get_placeholder(&self) -> Vec<u8>;
fn fulfill_symbol(&mut self, s: &T, p: SymbolPosition) -> ();
fn get_lex(a: Option<Vec<String>>) -> Self
where
Self: Sized;
}
pub trait PtrSize: Copy + Clone + std::str::FromStr<Err = std::num::ParseIntError> + Sized {
fn from_int<T: Integral>(a: T) -> Self;
fn extract_int<T: Integral>(&self) -> T;
fn add_int<T: Integral>(&mut self, a: T) -> ();
fn add_ptr(&mut self, a: Self) -> ();
}
pub trait DatSize: Copy + Clone + std::str::FromStr<Err = std::num::ParseIntError> + Sized {
fn from_int<T: Integral>(a: T) -> Self;
fn extract_int<T: Integral>(&self) -> T;
}
pub trait DisSize: Copy + Clone + std::str::FromStr<Err = std::num::ParseIntError> + Sized {}
pub trait Integral:
num_traits::WrappingNeg
+ num_traits::NumAssign
+ num_traits::cast::FromPrimitive
+ num_traits::cast::NumCast
+ Copy
+ Clone
{
}
impl<T> Integral for T where
T: num_traits::WrappingNeg
+ num_traits::NumAssign
+ num_traits::cast::FromPrimitive
+ num_traits::cast::NumCast
+ Copy
+ Clone
{
}
#[derive(Copy, Clone)]
pub struct GenScal<T: Integral> {
pub i: T,
}
impl<T: Integral> std::str::FromStr for GenScal<T> {
type Err = std::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
i: parse_ukr::<T>(s).unwrap(),
})
}
}
impl<T: Integral> PtrSize for GenScal<T> {
fn from_int<E: Integral>(a: E) -> Self {
Self {
i: num_traits::cast::cast(a).unwrap(),
}
}
fn extract_int<E: Integral>(&self) -> E {
num_traits::cast::cast(self.i).unwrap()
}
fn add_int<E: Integral>(&mut self, a: E) -> () {
self.i += num_traits::cast::cast(a).unwrap()
}
fn add_ptr(&mut self, a: Self) -> () {
self.i += a.i
}
}
impl<T: Integral> DatSize for GenScal<T> {
fn from_int<E: Integral>(a: E) -> Self {
Self {
i: num_traits::cast::cast(a).unwrap(),
}
}
fn extract_int<E: Integral>(&self) -> E {
num_traits::cast::cast(self.i).unwrap()
}
}
impl<T: Integral> DisSize for GenScal<T> {}
#[derive(Copy, Clone)]
pub struct Gen12 {
pub i: u16,
}
impl std::str::FromStr for Gen12 {
type Err = std::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
i: parse_ukr::<u16>(s).unwrap() & 0xfff,
})
}
}
impl PtrSize for Gen12 {
fn from_int<E: Integral>(a: E) -> Self {
Self {
i: num_traits::cast::cast::<E, u16>(a).unwrap() & 0xfffu16,
}
}
fn extract_int<E: Integral>(&self) -> E {
num_traits::cast::cast(self.i).unwrap()
}
fn add_int<E: Integral>(&mut self, a: E) -> () {
self.i += num_traits::cast::cast::<E, u16>(a).unwrap();
self.i &= 0xfff;
}
fn add_ptr(&mut self, a: Self) -> () {
self.i += a.i;
self.i &= 0xfff;
}
}
impl DatSize for Gen12 {
fn from_int<E: Integral>(a: E) -> Self {
Self {
i: num_traits::cast::cast::<E, u16>(a).unwrap() | 0xfffu16,
}
}
fn extract_int<E: Integral>(&self) -> E {
num_traits::cast::cast(self.i).unwrap()
}
}
impl DisSize for Gen12 {}
fn uw_aid<T, E>(r: Result<T, E>) -> T {
match r {
Ok(a) => a,
Err(_) => lpanic("unwrapping failed"),
}
}
fn parse_ukr<T: Integral>(s: &str) -> Option<T> {
if s.len() == 0 {
return None;
}
let sign = if s.chars().next() == Some('-') { 1 } else { 0 };
let v: T;
let sl = &s[sign..];
if sl.starts_with("0x") {
v = uw_aid(T::from_str_radix(&sl[2..], 16));
} else if sl.starts_with("0b") {
v = uw_aid(T::from_str_radix(&sl[2..], 2));
} else if sl.starts_with("0d") {
v = uw_aid(T::from_str_radix(&sl[2..], 12));
} else if sl.starts_with("0") {
v = uw_aid(T::from_str_radix(&sl[1..], 8));
} else {
v = uw_aid(T::from_str_radix(sl, 10));
}
Some(if sign == 1 { v.wrapping_neg() } else { v })
}
pub trait ArchReg: Copy + Clone + std::str::FromStr<Err = std::num::ParseIntError> + Sized {}
pub type RcSym = std::rc::Rc<str>;
#[derive(Clone)]
pub enum ArgSymbol<T: PtrSize, U: DatSize> {
UnknownPointer(RcSym),
UnknownData(RcSym),
Pointer(Box<T>),
Data(Box<U>),
}
impl<T: PtrSize, U: DatSize> ArgSymbol<T, U> {
pub fn unwrap_unknown_ptr(&self) -> Option<RcSym> {
if let ArgSymbol::UnknownPointer(n) = self {
return Some(n.clone());
} else {
return None;
}
}
pub fn unwrap_unknown_data(&self) -> Option<RcSym> {
if let ArgSymbol::UnknownData(n) = self {
return Some(n.clone());
} else {
return None;
}
}
pub fn unwrap_ptr(&self) -> Option<&Box<T>> {
if let ArgSymbol::Pointer(n) = self {
return Some(n);
} else {
return None;
}
}
pub fn unwrap_data(&self) -> Option<&Box<U>> {
if let ArgSymbol::Data(n) = self {
return Some(n);
} else {
return None;
}
}
}
pub enum ArchArg<T: PtrSize, U: DatSize, V: DisSize, W: ArchReg> {
Direct(ArgSymbol<T, U>),
Memory(ArchMem<T, U, W>),
Register(ArchIndivReg<V, W>),
}
impl<T: PtrSize, U: DatSize, V: DisSize, W: ArchReg> ArchArg<T, U, V, W> {
pub fn unwrap_direct(&self) -> Option<&ArgSymbol<T, U>> {
if let ArchArg::Direct(n) = self {
return Some(n);
} else {
return None;
}
}
pub fn unwrap_memory(&self) -> Option<&ArchMem<T, U, W>> {
if let ArchArg::Memory(n) = self {
return Some(n);
} else {
return None;
}
}
pub fn unwrap_register(&self) -> Option<&ArchIndivReg<V, W>> {
if let ArchArg::Register(n) = self {
return Some(n);
} else {
return None;
}
}
}
pub struct ArchMem<T: PtrSize, U: DatSize, W: ArchReg> {
pub segr: Option<Box<W>>,
pub v: ArgSymbol<T, U>,
}
pub struct ArchIndivReg<V: DisSize, W: ArchReg> {
pub segr: Option<Box<W>>,
pub disp: Option<Box<V>>,
pub reg: Box<W>,
pub shift: Option<(u8, Box<W>)>,
}
type RegClauseInfo<V, W> = (Option<Box<V>>, Box<W>, Option<(u8, Box<W>)>);
pub fn parse_arg<T: PtrSize, U: DatSize, V: DisSize, W: ArchReg>(
s: &String,
) -> Option<ArchArg<T, U, V, W>> {
let cv: Vec<String> = s.split(":").map(|x| x.to_string()).collect();
if cv.len() != 1 {
if cv.len() == 2 {
let sr: Box<W> = Box::new(W::from_str(&cv[0]).unwrap());
if cv[1].contains('%') {
let vs: RegClauseInfo<V, W> = parse_reg_clause(&cv[1]);
return Some(ArchArg::Register(ArchIndivReg {
segr: Some(sr),
disp: vs.0,
reg: vs.1,
shift: vs.2,
}));
} else {
return Some(ArchArg::Memory(ArchMem {
segr: Some(sr),
v: extract_mem_symbol(&cv[1]),
}));
}
} else {
return None;
}
}
if cv[0].contains('%') {
let vs: RegClauseInfo<V, W> = parse_reg_clause(&cv[0]);
return Some(ArchArg::Register(ArchIndivReg {
segr: None,
disp: vs.0,
reg: vs.1,
shift: vs.2,
}));
} else {
if cv[0].chars().next() == Some('$') {
return Some(ArchArg::Direct(get_direct_value(
&cv[0].split_at(1).1.to_string(),
)));
} else {
return Some(ArchArg::Memory(ArchMem {
segr: None,
v: extract_mem_symbol(&cv[0]),
}));
}
}
}
fn get_direct_value<T: PtrSize, U: DatSize>(s: &String) -> ArgSymbol<T, U> {
if s.chars().next().unwrap().is_numeric() {
return ArgSymbol::Data(Box::new(U::from_str(s).unwrap()));
} else {
return ArgSymbol::UnknownData(RcSym::from(s.as_str()));
}
}
fn parse_reg_clause<V: DisSize, W: ArchReg>(s: &String) -> RegClauseInfo<V, W> {
let mut disp: Option<Box<V>> = None;
let mut p: String = s.clone();
if p.contains('(') {
let v: Vec<String> = p.split('(').map(|x| x.to_string()).collect();
p = v[1].trim_end_matches(')').to_string();
if v[0] != "" {
disp = Some(Box::new(V::from_str(&v[0]).unwrap()));
}
}
let secs: Vec<String> = p.split(',').map(|x| x.to_string()).collect();
let reg: Box<W> = Box::new(W::from_str(&secs[0]).unwrap());
let mut shift: Option<(u8, Box<W>)> = None;
if secs.len() >= 2 {
shift = Some((
if secs.len() == 3 {
secs[2].parse().unwrap()
} else {
0
},
Box::new(W::from_str(&secs[1]).unwrap()),
));
}
(disp, reg, shift)
}
fn extract_mem_symbol<T: PtrSize, U: DatSize>(s: &String) -> ArgSymbol<T, U> {
let ns: String = trim_parentheses(s);
if ns.chars().next().unwrap().is_numeric() || ns.chars().next().unwrap() == '-' {
return ArgSymbol::Pointer(Box::new(T::from_str(&ns).unwrap()));
} else {
return ArgSymbol::UnknownPointer(RcSym::from(ns.as_str()));
}
}
fn trim_parentheses(s: &String) -> String {
s.trim_start_matches('(').trim_end_matches(')').to_string()
}
macro_rules! be_mcr {
($nm:ident,$u:ty) => {
pub struct $nm {
x: ArgSymbol<GenScal<$u>, GenScal<$u>>,
}
impl<T: SymConv> ArchMcrInst<T> for $nm {
fn get_output_bytes(&self) -> Vec<u8> {
Vec::from(self.x.unwrap_ptr().unwrap().i.to_be_bytes())
}
fn get_lex(a: Option<Vec<String>>) -> Self {
Self {
x: extract_mem_symbol(&a.unwrap()[0])
}
}
fn get_length(&self) -> SymbolPosition {
std::mem::size_of::<$u>()
}
fn get_symbols(&self) -> USIWrap {
match self.x {
crate::bbu::ArgSymbol::UnknownPointer(ref a) => Some(vec![(a.clone(), 0)]),
_ => None
}
}
fn get_placeholder(&self) -> Vec<u8> {
unimplemented!()
}
fn fulfill_symbol(&mut self, s: &T, p: SymbolPosition) -> () {
match p {
0 => {
self.x = ArgSymbol::Pointer(Box::new(s.into_ptr::<GenScal<$u>, $u>()))
}
_ => lpanic("bbu: bemcr: unknown positional"),
}
}
fn check_symbols(&self) -> bool {
match self.x {
ArgSymbol::UnknownPointer(_) => true,
_ => false,
}
}
}
};
}
be_mcr!(Bu8, u8);
be_mcr!(Bu16, u16);