Skip to content

Commit

Permalink
Merge pull request #344 from yeslogic/int-hints
Browse files Browse the repository at this point in the history
Add formatting hints to numbers
  • Loading branch information
wezm authored Apr 26, 2022
2 parents a181ad8 + e177c4a commit d1f609c
Show file tree
Hide file tree
Showing 25 changed files with 464 additions and 188 deletions.
100 changes: 95 additions & 5 deletions fathom/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,14 +403,24 @@ def_prims! {
PosAddU64 => "pos_add_u64",
}

/// Constants
/// Formatting style for integers
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub enum UIntStyle {
Binary,
Decimal,
Hexadecimal,
/// A [four-character code](https://en.wikipedia.org/wiki/FourCC) (big-endian)
Ascii,
}

/// Constants
#[derive(Debug, Copy, Clone, PartialOrd)]
pub enum Const {
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U8(u8, UIntStyle),
U16(u16, UIntStyle),
U32(u32, UIntStyle),
U64(u64, UIntStyle),
S8(i8),
S16(i16),
S32(i32),
Expand All @@ -422,6 +432,86 @@ pub enum Const {
Ref(u64),
}

impl PartialEq for Const {
fn eq(&self, other: &Self) -> bool {
match (*self, *other) {
(Const::Bool(a), Const::Bool(b)) => a == b,
(Const::U8(a, _), Const::U8(b, _)) => a == b,
(Const::U16(a, _), Const::U16(b, _)) => a == b,
(Const::U32(a, _), Const::U32(b, _)) => a == b,
(Const::U64(a, _), Const::U64(b, _)) => a == b,
(Const::S8(a), Const::S8(b)) => a == b,
(Const::S16(a), Const::S16(b)) => a == b,
(Const::S32(a), Const::S32(b)) => a == b,
(Const::S64(a), Const::S64(b)) => a == b,
(Const::F32(a), Const::F32(b)) => a == b,
(Const::F64(a), Const::F64(b)) => a == b,
(Const::Pos(a), Const::Pos(b)) => a == b,
(Const::Ref(a), Const::Ref(b)) => a == b,
_ => false,
}
}
}

pub trait ToBeBytes<const N: usize> {
fn to_be_bytes(self) -> [u8; N];
}

macro_rules! impl_styled_uint {
($($ty:ty),*) => {
$(
impl ToBeBytes<{std::mem::size_of::<$ty>()}> for &$ty {
fn to_be_bytes(self) -> [u8; std::mem::size_of::<$ty>()] {
<$ty>::to_be_bytes(*self)
}
}

impl UIntStyled<{std::mem::size_of::<$ty>()}> for &$ty {}
)*
};
}

impl_styled_uint!(u8, u16, u32, u64);

pub trait UIntStyled<const N: usize>:
std::fmt::Display + Copy + std::fmt::LowerHex + std::fmt::Binary + ToBeBytes<N>
{
}

impl UIntStyle {
pub fn format<T: UIntStyled<N>, const N: usize>(&self, number: T) -> String {
match self {
UIntStyle::Binary => format!("0b{:b}", number),
UIntStyle::Decimal => number.to_string(),
UIntStyle::Hexadecimal => format!("0x{:x}", number),
UIntStyle::Ascii => {
let bytes = number.to_be_bytes();
if bytes.iter().all(|c| c.is_ascii() && !c.is_ascii_control()) {
let s = std::str::from_utf8(&bytes).unwrap(); // unwrap safe due to above check
format!("\"{}\"", s)
} else {
format!("0x{:x}", number)
}
}
}
}

pub fn merge(left: UIntStyle, right: UIntStyle) -> UIntStyle {
use UIntStyle::*;

match (left, right) {
// If one is the default style, then return the other
(Decimal, style) | (style, Decimal) => style,
// When both styles are the same. Note: (Decimal, Decimal) is handled above
(Binary, Binary) => Binary,
(Hexadecimal, Hexadecimal) => Hexadecimal,
(Ascii, Ascii) => Ascii,
// Otherwise use the default style
(_, _) => Decimal,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
24 changes: 12 additions & 12 deletions fathom/src/core/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::io::{self, Read, Seek, SeekFrom};
use std::sync::Arc;

use crate::core::semantics::{self, ArcValue, Elim, Head, Value};
use crate::core::{Const, Prim};
use crate::core::{Const, Prim, UIntStyle};
use crate::env::{EnvLen, SliceEnv};

pub struct Context<'arena, 'env> {
Expand Down Expand Up @@ -127,13 +127,13 @@ impl<'arena, 'env> Context<'arena, 'env> {

match (prim, &slice[..]) {
(Prim::FormatSucceed, [_, Fun(r#elem)]) => Ok(r#elem.clone()),
(Prim::FormatU8, []) => read_const(reader, Const::U8, read_u8),
(Prim::FormatU16Be, []) => read_const(reader, Const::U16, read_u16be),
(Prim::FormatU16Le, []) => read_const(reader, Const::U16, read_u16le),
(Prim::FormatU32Be, []) => read_const(reader, Const::U32, read_u32be),
(Prim::FormatU32Le, []) => read_const(reader, Const::U32, read_u32le),
(Prim::FormatU64Be, []) => read_const(reader, Const::U64, read_u64be),
(Prim::FormatU64Le, []) => read_const(reader, Const::U64, read_u64le),
(Prim::FormatU8, []) => read_const(reader, |num| Const::U8(num, UIntStyle::Decimal), read_u8),
(Prim::FormatU16Be, []) => read_const(reader, |num| Const::U16(num, UIntStyle::Decimal), read_u16be),
(Prim::FormatU16Le, []) => read_const(reader, |num| Const::U16(num, UIntStyle::Decimal), read_u16le),
(Prim::FormatU32Be, []) => read_const(reader, |num| Const::U32(num, UIntStyle::Decimal), read_u32be),
(Prim::FormatU32Le, []) => read_const(reader, |num| Const::U32(num, UIntStyle::Decimal), read_u32le),
(Prim::FormatU64Be, []) => read_const(reader, |num| Const::U64(num, UIntStyle::Decimal), read_u64be),
(Prim::FormatU64Le, []) => read_const(reader, |num| Const::U64(num, UIntStyle::Decimal), read_u64le),
(Prim::FormatS8, []) => read_const(reader, Const::S8, read_s8),
(Prim::FormatS16Be, []) => read_const(reader, Const::S16, read_s16be),
(Prim::FormatS16Le, []) => read_const(reader, Const::S16, read_s16le),
Expand Down Expand Up @@ -164,10 +164,10 @@ impl<'arena, 'env> Context<'arena, 'env> {
elem_format: &ArcValue<'arena>,
) -> io::Result<ArcValue<'arena>> {
let (len, mut elem_exprs) = match self.elim_context().force(len).as_ref() {
Value::Const(Const::U8(len)) => (*len as u64, Vec::with_capacity(*len as usize)),
Value::Const(Const::U16(len)) => (*len as u64, Vec::with_capacity(*len as usize)),
Value::Const(Const::U32(len)) => (*len as u64, Vec::with_capacity(*len as usize)),
Value::Const(Const::U64(len)) => (*len as u64, Vec::with_capacity(*len as usize)),
Value::Const(Const::U8(len, _)) => (*len as u64, Vec::with_capacity(*len as usize)),
Value::Const(Const::U16(len, _)) => (*len as u64, Vec::with_capacity(*len as usize)),
Value::Const(Const::U32(len, _)) => (*len as u64, Vec::with_capacity(*len as usize)),
Value::Const(Const::U64(len, _)) => (*len as u64, Vec::with_capacity(*len as usize)),
_ => return Err(io::Error::new(io::ErrorKind::Other, "invalid array length")),
};

Expand Down
90 changes: 48 additions & 42 deletions fathom/src/core/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::panic::panic_any;
use std::sync::Arc;

use crate::alloc::SliceVec;
use crate::core::{Const, EntryInfo, Prim, Term};
use crate::core::{Const, EntryInfo, Prim, Term, UIntStyle};
use crate::env::{EnvLen, GlobalVar, SharedEnv, SliceEnv};
use crate::StringId;

Expand Down Expand Up @@ -357,7 +357,13 @@ macro_rules! step {
macro_rules! const_step {
([$($input:ident : $Input:ident),*] => $output:expr) => {
step!(_, [$($input),*] => match ($($input.as_ref(),)*) {
($(Value::Const(Const::$Input($input)),)*) => Arc::new(Value::Const($output)),
($(Value::Const(Const::$Input($input, ..)),)*) => Arc::new(Value::Const($output)),
_ => return None,
})
};
([$($input:ident , $style:ident : $Input:ident),*] => $output:expr) => {
step!(_, [$($input),*] => match ($($input.as_ref(),)*) {
($(Value::Const(Const::$Input($input, $style)),)*) => Arc::new(Value::Const($output)),
_ => return None,
})
};
Expand All @@ -384,67 +390,67 @@ fn prim_step(prim: Prim) -> Option<PrimStep> {
Prim::U8Lt => const_step!([x: U8, y: U8] => Const::Bool(x < y)),
Prim::U8Gte => const_step!([x: U8, y: U8] => Const::Bool(x >= y)),
Prim::U8Lte => const_step!([x: U8, y: U8] => Const::Bool(x <= y)),
Prim::U8Add => const_step!([x: U8, y: U8] => Const::U8(u8::checked_add(*x, *y)?)),
Prim::U8Sub => const_step!([x: U8, y: U8] => Const::U8(u8::checked_sub(*x, *y)?)),
Prim::U8Mul => const_step!([x: U8, y: U8] => Const::U8(u8::checked_mul(*x, *y)?)),
Prim::U8Div => const_step!([x: U8, y: U8] => Const::U8(u8::checked_div(*x, *y)?)),
Prim::U8Not => const_step!([x: U8] => Const::U8(u8::not(*x))),
Prim::U8Shl => const_step!([x: U8, y: U8] => Const::U8(u8::checked_shl(*x, u32::from(*y))?)),
Prim::U8Shr => const_step!([x: U8, y: U8] => Const::U8(u8::checked_shr(*x, u32::from(*y))?)),
Prim::U8And => const_step!([x: U8, y: U8] => Const::U8(u8::bitand(*x, *y))),
Prim::U8Or => const_step!([x: U8, y: U8] => Const::U8(u8::bitor(*x, *y))),
Prim::U8Xor => const_step!([x: U8, y: U8] => Const::U8(u8::bitxor(*x, *y))),
Prim::U8Add => const_step!([x, xst: U8, y, yst: U8] => Const::U8(u8::checked_add(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U8Sub => const_step!([x, xst: U8, y, yst: U8] => Const::U8(u8::checked_sub(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U8Mul => const_step!([x, xst: U8, y, yst: U8] => Const::U8(u8::checked_mul(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U8Div => const_step!([x, xst: U8, y, yst: U8] => Const::U8(u8::checked_div(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U8Not => const_step!([x, style: U8] => Const::U8(u8::not(*x), *style)),
Prim::U8Shl => const_step!([x, xst: U8, y, _yst: U8] => Const::U8(u8::checked_shl(*x, u32::from(*y))?, *xst)),
Prim::U8Shr => const_step!([x, xst: U8, y, _yst: U8] => Const::U8(u8::checked_shr(*x, u32::from(*y))?, *xst)),
Prim::U8And => const_step!([x, xst: U8, y, yst: U8] => Const::U8(u8::bitand(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U8Or => const_step!([x, xst: U8, y, yst: U8] => Const::U8(u8::bitor(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U8Xor => const_step!([x, xst: U8, y, yst: U8] => Const::U8(u8::bitxor(*x, *y), UIntStyle::merge(*xst, *yst))),

Prim::U16Eq => const_step!([x: U16, y: U16] => Const::Bool(x == y)),
Prim::U16Neq => const_step!([x: U16, y: U16] => Const::Bool(x != y)),
Prim::U16Gt => const_step!([x: U16, y: U16] => Const::Bool(x > y)),
Prim::U16Lt => const_step!([x: U16, y: U16] => Const::Bool(x < y)),
Prim::U16Gte => const_step!([x: U16, y: U16] => Const::Bool(x >= y)),
Prim::U16Lte => const_step!([x: U16, y: U16] => Const::Bool(x <= y)),
Prim::U16Add => const_step!([x: U16, y: U16] => Const::U16(u16::checked_add(*x, *y)?)),
Prim::U16Sub => const_step!([x: U16, y: U16] => Const::U16(u16::checked_sub(*x, *y)?)),
Prim::U16Mul => const_step!([x: U16, y: U16] => Const::U16(u16::checked_mul(*x, *y)?)),
Prim::U16Div => const_step!([x: U16, y: U16] => Const::U16(u16::checked_div(*x, *y)?)),
Prim::U16Not => const_step!([x: U16] => Const::U16(u16::not(*x))),
Prim::U16Shl => const_step!([x: U16, y: U8] => Const::U16(u16::checked_shl(*x, u32::from(*y))?)),
Prim::U16Shr => const_step!([x: U16, y: U8] => Const::U16(u16::checked_shr(*x, u32::from(*y))?)),
Prim::U16And => const_step!([x: U16, y: U16] => Const::U16(u16::bitand(*x, *y))),
Prim::U16Or => const_step!([x: U16, y: U16] => Const::U16(u16::bitor(*x, *y))),
Prim::U16Xor => const_step!([x: U16, y: U16] => Const::U16(u16::bitxor(*x, *y))),
Prim::U16Add => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::checked_add(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U16Sub => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::checked_sub(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U16Mul => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::checked_mul(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U16Div => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::checked_div(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U16Not => const_step!([x: U16] => Const::U16(u16::not(*x), UIntStyle::Decimal)),
Prim::U16Shl => const_step!([x, xst: U16, y, _yst: U8] => Const::U16(u16::checked_shl(*x, u32::from(*y))?, *xst)),
Prim::U16Shr => const_step!([x, xst: U16, y, _yst: U8] => Const::U16(u16::checked_shr(*x, u32::from(*y))?, *xst)),
Prim::U16And => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::bitand(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U16Or => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::bitor(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U16Xor => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::bitxor(*x, *y), UIntStyle::merge(*xst, *yst))),

Prim::U32Eq => const_step!([x: U32, y: U32] => Const::Bool(x == y)),
Prim::U32Neq => const_step!([x: U32, y: U32] => Const::Bool(x != y)),
Prim::U32Gt => const_step!([x: U32, y: U32] => Const::Bool(x > y)),
Prim::U32Lt => const_step!([x: U32, y: U32] => Const::Bool(x < y)),
Prim::U32Gte => const_step!([x: U32, y: U32] => Const::Bool(x >= y)),
Prim::U32Lte => const_step!([x: U32, y: U32] => Const::Bool(x <= y)),
Prim::U32Add => const_step!([x: U32, y: U32] => Const::U32(u32::checked_add(*x, *y)?)),
Prim::U32Sub => const_step!([x: U32, y: U32] => Const::U32(u32::checked_sub(*x, *y)?)),
Prim::U32Mul => const_step!([x: U32, y: U32] => Const::U32(u32::checked_mul(*x, *y)?)),
Prim::U32Div => const_step!([x: U32, y: U32] => Const::U32(u32::checked_div(*x, *y)?)),
Prim::U32Not => const_step!([x: U32] => Const::U32(u32::not(*x))),
Prim::U32Shl => const_step!([x: U32, y: U8] => Const::U32(u32::checked_shl(*x, u32::from(*y))?)),
Prim::U32Shr => const_step!([x: U32, y: U8] => Const::U32(u32::checked_shr(*x, u32::from(*y))?)),
Prim::U32And => const_step!([x: U32, y: U32] => Const::U32(u32::bitand(*x, *y))),
Prim::U32Or => const_step!([x: U32, y: U32] => Const::U32(u32::bitor(*x, *y))),
Prim::U32Xor => const_step!([x: U32, y: U32] => Const::U32(u32::bitxor(*x, *y))),
Prim::U32Add => const_step!([x, xst: U32, y, yst: U32] => Const::U32(u32::checked_add(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U32Sub => const_step!([x, xst: U32, y, yst: U32] => Const::U32(u32::checked_sub(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U32Mul => const_step!([x, xst: U32, y, yst: U32] => Const::U32(u32::checked_mul(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U32Div => const_step!([x, xst: U32, y, yst: U32] => Const::U32(u32::checked_div(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U32Not => const_step!([x: U32] => Const::U32(u32::not(*x), UIntStyle::Decimal)),
Prim::U32Shl => const_step!([x, xst: U32, y, _yst: U8] => Const::U32(u32::checked_shl(*x, u32::from(*y))?, *xst)),
Prim::U32Shr => const_step!([x, xst: U32, y, _yst: U8] => Const::U32(u32::checked_shr(*x, u32::from(*y))?, *xst)),
Prim::U32And => const_step!([x, xst: U32, y, yst: U32] => Const::U32(u32::bitand(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U32Or => const_step!([x, xst: U32, y, yst: U32] => Const::U32(u32::bitor(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U32Xor => const_step!([x, xst: U32, y, yst: U32] => Const::U32(u32::bitxor(*x, *y), UIntStyle::merge(*xst, *yst))),

Prim::U64Eq => const_step!([x: U64, y: U64] => Const::Bool(x == y)),
Prim::U64Neq => const_step!([x: U64, y: U64] => Const::Bool(x != y)),
Prim::U64Gt => const_step!([x: U64, y: U64] => Const::Bool(x > y)),
Prim::U64Lt => const_step!([x: U64, y: U64] => Const::Bool(x < y)),
Prim::U64Gte => const_step!([x: U64, y: U64] => Const::Bool(x >= y)),
Prim::U64Lte => const_step!([x: U64, y: U64] => Const::Bool(x <= y)),
Prim::U64Add => const_step!([x: U64, y: U64] => Const::U64(u64::checked_add(*x, *y)?)),
Prim::U64Sub => const_step!([x: U64, y: U64] => Const::U64(u64::checked_sub(*x, *y)?)),
Prim::U64Mul => const_step!([x: U64, y: U64] => Const::U64(u64::checked_mul(*x, *y)?)),
Prim::U64Div => const_step!([x: U64, y: U64] => Const::U64(u64::checked_div(*x, *y)?)),
Prim::U64Not => const_step!([x: U64] => Const::U64(u64::not(*x))),
Prim::U64Shl => const_step!([x: U64, y: U8] => Const::U64(u64::checked_shl(*x, u32::from(*y))?)),
Prim::U64Shr => const_step!([x: U64, y: U8] => Const::U64(u64::checked_shr(*x, u32::from(*y))?)),
Prim::U64And => const_step!([x: U64, y: U64] => Const::U64(u64::bitand(*x, *y))),
Prim::U64Or => const_step!([x: U64, y: U64] => Const::U64(u64::bitor(*x, *y))),
Prim::U64Xor => const_step!([x: U64, y: U64] => Const::U64(u64::bitxor(*x, *y))),
Prim::U64Add => const_step!([x, xst: U64, y, yst: U64] => Const::U64(u64::checked_add(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U64Sub => const_step!([x, xst: U64, y, yst: U64] => Const::U64(u64::checked_sub(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U64Mul => const_step!([x, xst: U64, y, yst: U64] => Const::U64(u64::checked_mul(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U64Div => const_step!([x, xst: U64, y, yst: U64] => Const::U64(u64::checked_div(*x, *y)?, UIntStyle::merge(*xst, *yst))),
Prim::U64Not => const_step!([x: U64] => Const::U64(u64::not(*x), UIntStyle::Decimal)),
Prim::U64Shl => const_step!([x, xst: U64, y, _yst: U8] => Const::U64(u64::checked_shl(*x, u32::from(*y))?, *xst)),
Prim::U64Shr => const_step!([x, xst: U64, y, _yst: U8] => Const::U64(u64::checked_shr(*x, u32::from(*y))?, *xst)),
Prim::U64And => const_step!([x, xst: U64, y, yst: U64] => Const::U64(u64::bitand(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U64Or => const_step!([x, xst: U64, y, yst: U64] => Const::U64(u64::bitor(*x, *y), UIntStyle::merge(*xst, *yst))),
Prim::U64Xor => const_step!([x, xst: U64, y, yst: U64] => Const::U64(u64::bitxor(*x, *y), UIntStyle::merge(*xst, *yst))),

Prim::S8Eq => const_step!([x: S8, y: S8] => Const::Bool(x == y)),
Prim::S8Neq => const_step!([x: S8, y: S8] => Const::Bool(x != y)),
Expand Down
Loading

0 comments on commit d1f609c

Please sign in to comment.